So today we’re going to be making an image gallery where the images zoom out on click. We’ll also add a close button for closing the images after they’ve been zoomed out. Best of all, we’re going to be doing it all with just CSS!
It’s best to keep this non-scrollable, since :target
makes the page jump to the object, which would be rather annoying on a scrollable website. If you need to, we can override this with a simple line of Javascript, which you can find at the end of this tutorial.
Support
Number of Users Who Can Use | |
Full Demo | 55.93% |
Without Transitions | 72.47% |
Lets Begin
To start, lets take a look at the HTML. It consists of a large parent element which contains several holders, each of which act as a single image. Each holder has a few features such as a close button, an image, and a link which allows us to click the image to expand it. Each ‘expand’ link is linked to the holder parent, so that we can use :target
in CSS.
<div id="images-box"> <div class="holder"> <div id="image-1" class="image-lightbox"> <span class="close"><a href="#">X</a></span> <img src="1.jpg" alt="earth!"> <a class="expand" href="#image-1"></a> </div> </div> <div class="holder"> <div id="image-2" class="image-lightbox"> <span class="close"><a href="#">X</a></span> <img src="2.jpg" alt="earth!"> <a class="expand" href="#image-2"></a> </div> </div> <div class="holder"> <div id="image-3" class="image-lightbox"> <span class="close"><a href="#">X</a></span> <img src="3.jpg" alt="earth!"> <a class="expand" href="#image-3"></a> </div> </div> </div>
The CSS
The CSS isn’t that challenging. To begin, lets style the parent holder elements.
#images-box { /* The total width of the image-box, mainly for centering */ width: 850px; margin: 0px auto; position: relative; top: 70px; } .image-lightbox img { /* Inherit the width and height from the parent element */ width: inherit; height: inherit; z-index: 3000; } .holder { /* The width and height, you can change these */ width: 250px; height: 166px; /* Float left, so everything aligns right */ float: left; margin: 0 20px 0 0; } .image-lightbox { /* Inherit width and height from the .holder */ width: inherit; height: inherit; padding: 10px; /* Box shadow */ box-shadow: 0px 0px 10px rgba(0,0,0,0.1); background: #fff; border-radius: 5px; /* Position absolutely so we can zoom it out later */ position: absolute; top: 0; font-family: Arial, sans-serif; /* Transitions to provide some eye candy */ -webkit-transition: all ease-in 0.5s; -moz-transition: all ease-in 0.5s; -ms-transition: all ease-in 0.5s; -o-transition: all ease-in 0.5s; }
Next we need to style the internal elements. I set the <span>
elements to display: none
so that we can make the close button appear when the user clicks on the image. The anchor has been altered to fill the entire parent element, making it all clickable.
.image-lightbox span { display: none; } .image-lightbox .expand { width: 100%; height: 100%; position: absolute; top: 0; z-index: 4000; background: rgba(0,0,0,0); /* Fixes an IE bug */ left: 0; } .image-lightbox .close { position: absolute; width: 20px; height: 20px; right: 20px; top: 20px; } .image-lightbox .close a { height: auto; width: auto; padding: 5px 10px; color: #fff; text-decoration: none; background: #22272c; box-shadow: inset 0px 24px 20px -15px rgba(255, 255, 255, 0.1), inset 0px 0px 10px rgba(0,0,0,0.4), 0px 0px 30px rgba(255,255,255,0.4); border-radius: 5px; font-weight: bold; float: right; } .image-lightbox .close a:hover { box-shadow: inset 0px -24px 20px -15px rgba(255, 255, 255, 0.01), inset 0px 0px 10px rgba(0,0,0,0.4), 0px 0px 20px rgba(255,255,255,0.4); }
Before we continue onto the :target
stuff, some positioning is required. If you want to add more images you’ll have to add some stuff here.
div#image-1 { left: 0; } div#image-2 { left: 290px; } div#image-3 { left: 580px; }
The actual targeting of elements isn’t that hard. We just need to change the position and z-index, oh, and change some of the element’s display
property.
div[id^=image]:target { width: 450px; height: 300px; z-index: 5000; top: 50px; left: 200px; } div[id^=image]:target .close { display: block; } div[id^=image]:target .expand { display: none; } div#image-1:target, div#image-2:target, div#image-3:target { left: 200px; }
And that’s it! Here’s the full CSS as usual, in case you just want to copy and paste. Have a good day, check out the demo, and if you feel so inclined, click that tweet button.
#images-box { /* The total width of the image-box, mainly for centering */ width: 850px; margin: 0px auto; position: relative; top: 70px; } .image-lightbox img { /* Inherit the width and height from the parent element */ width: inherit; height: inherit; } .holder { /* The width and height, you can change these */ width: 250px; height: 166px; /* Float left, so everything aligns right */ float: left; margin: 0 20px 0 0; } .image-lightbox { /* Inherit width and height from the .holder */ width: inherit; height: inherit; padding: 10px; /* Box shadow */ box-shadow: 0px 0px 10px rgba(0,0,0,0.1); background: #fff; border-radius: 5px; /* Position absolutely so we can zoom it out later */ position: absolute; top: 0; font-family: Arial, sans-serif; /* Transitions to provide some eye candy */ -webkit-transition: all ease-in 0.5s; -moz-transition: all ease-in 0.5s; -ms-transition: all ease-in 0.5s; -o-transition: all ease-in 0.5s; } .image-lightbox span { display: none; } .image-lightbox .expand { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } .image-lightbox .close { position: absolute; width: 20px; height: 20px; right: 20px; top: 20px; } .image-lightbox .close a { height: auto; width: auto; padding: 5px 10px; color: #fff; text-decoration: none; background: #22272c; box-shadow: inset 0px 24px 20px -15px rgba(255, 255, 255, 0.1), inset 0px 0px 10px rgba(0,0,0,0.4), 0px 0px 30px rgba(255,255,255,0.4); border-radius: 5px; font-weight: bold; float: right; } .close a:hover { box-shadow: inset 0px -24px 20px -15px rgba(255, 255, 255, 0.01), inset 0px 0px 10px rgba(0,0,0,0.4), 0px 0px 20px rgba(255,255,255,0.4); } div[id^=image]:target { width: 450px; height: 300px; z-index: 5000; top: 50px; left: 200px; } div[id^=image]:target .close { display: block; } div[id^=image]:target .expand { display: none; } div#image-1:target, div#image-2:target, div#image-3:target { left: 200px; } div#image-1 { left: 0; } div#image-2 { left: 290px; } div#image-3 { left: 580px; }
Comments
The only thing I don’t like about this is that if I look at multiple pictures and then want to use the “back” button, I have to go through all of the photos I looked at again in order to go to the previous page.
Nice gallery! But the same problem for me with the navigation, adding a little of javascript could solve it? It would be nice to know how.
Just one question, If i put in 3 pictures on that row, how can i put in 3 different picture in a row below the 1st row?
You could copy and paste the code for the first row and it should work. You might have to change some stuff like positions though.
Your demo code and method simple and more efficient thanks for your help……
can you tell me how i can add more pictures. i need to put about 20 pic but i dont find the form to do it thanks for future helps
If you were to duplicated the entire HTML code and change ID to class you could add another row. You’d have to tidy it up a little though.
ok… so i’m trying to adjust the code to hold one portrait-style image and 2 landscapes, instead of all 3 being landscapes, and i’m having issues, as i’m not exactly a CSS expert… i gave the divs and spans related to the differently sized image their own ids, and that fixed the display, but the image, when clicked, expanded out horizontally like the others…. any suggestions?
thanks!
Hello There. I found your blog using msn. That is an extremely well written article. I will be sure to bookmark it and return to read extra of your useful info. Thanks for the post. I’ll definitely return.
Many thanks for your help. When I close a picture, the view goes back automaticly on the top of the page and I have to scroll down again to my gallery. Any idea to solve this ? I can’t figure it out by myself.
Hello, thanks a lot for your job! But I have the same issue like “quai20”.
“When I close a picture, the view goes back automaticly on the top of the page and I have to scroll down again to my gallery.” Do you have a soluce?
Thank you for your suggestions!
Probably the best solution is to record user scroll position when the user scrolls and then when they click the button set the scroll position to the recorded scroll position so it remains constant.
Hi Johnny,
Nop! :-(
on zooming on the image: record the Xoffset
on collapsing : recall the previously recorded XOffset
It does not work (maybe because of the URL change?)
ANyway I could by-pass the URL rewriting? ANy other suggestion?
Thanks anyway, nice job!
How do you make the pictures into more of a grid with multiple rows. Can you please give me the code? CSS3 HTML5?
Hi Sarah, i’m in the same boat and plan to do the following in the CSS:
3×3 grid
div#image-1 { left: 0; }
div#image-2 { left: 33%; }
div#image-3 { left: 66%; }
div#image-4 { top: 33% left: 0; }
div#image-5 { top: 33% left: 33%; }
div#image-6 { top: 33% left: 66%; }
div#image-7 { top: 66% left: 0; }
div#image-8 { top: 66% left: 33%; }
div#image-9 { top: 66% left: 66%; }
Hope this helps.
The problem that I am having with this tutorial though is when the image expands, it is locked inside its div, in my case, a sidebar. How do I go about expanding it to the center of the screen, and not its containing div? I’m sure the solution is simple but so far it is alluding me.
Hey Daniel!
I honestly think the best way to go about this is to simply reposition the divs when they are targeted vertically. As it stands now the divs are only being moved 200px to left, or -200px to the left to be centered in their rows. If you have 3 rows you might want to add top: 200px; so it appears centered.
Since this is CSS only we are limited and in jQuery we might append the selected image to the body giving us a bit more freedom. However if you’re sticking with just CSS this seems like the best idea to me.
Thanks for that, yea I am wanting to stay with just CSS so I’ll give it a go :)