CSS-Only Lightbox

Learn how a CSS-only powered image lightbox works and how to add fancy animations

CSS3Lightbox

Today we want to show you how to create a neat lightbox effect using only CSS. The idea is to have some thumbnails that are clickable, and once clicked, the respective large image is shown. Using CSS transitions and animations, we can make the large image appear in a fancy way.

With the help of the pseudo-class :target, we will be able to show the lightbox images and navigate through them.

The beautiful images are by Joanna Kustra and they are licensed under the Attribution-NonCommercial 3.0 Unported Creative Commons License.

Please note that this will only work with browsers that support the :target pseudo class.

Let’s do it!

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

The Markup

We want to show a set of thumbnails, each one having a title that will appear on hover. When clicking on a thumbnail, we want to show a large version of the image in an overlay container that will make the background a bit more opaque. So, let’s use an unordered list where each list item will contain a thumbnail and a division for the overlay with the respective large version of the image:

<ul class="lb-album">
	<li>
		<a href="#image-1">
			<img src="images/thumbs/1.jpg" alt="image01">
			<span>Pointe</span>
		</a>
		<div class="lb-overlay" id="image-1">
			<img src="images/full/1.jpg" alt="image01" />
			<div>
				<h3>pointe <span>/point/</h3>
				<p>Dance performed on the tips of the toes</p>
				<a href="#image-10" class="lb-prev">Prev</a>
				<a href="#image-2" class="lb-next">Next</a>
			</div>
			<a href="#page" class="lb-close">x Close</a>
		</div>
	</li>
	<li> 
		<!-- ... --> 
	</li>
</ul>

CSS3Lightbox01

The anchor for the thumbnail will point to the element with the id image-1 which is the division with the class lb-overlay. In order to navigate through the images, we will add two link elements that point to the previous and next (large) image.
In order to “close” the lightbox, we will somply click on the link with the class lb-close which points to the element with the ID page which is our body.

Note that we only use a navigation in the last demo.

Let’s beautify this naked markup.

The CSS

I’ll omit the vendor prefixes for some of the new properties here in order not to bloat the tutorial. You can, of course, find them in the download files.

Let’s give some basic layout to our unordered list and the thumbnails:

.lb-album{
	width: 900px;
	margin: 0 auto;
	font-family: 'BebasNeueRegular', 'Arial Narrow', Arial, sans-serif;
}
.lb-album li{
	float: left;
	margin: 5px;
	position: relative;
}
.lb-album li > a,
.lb-album li > a img{
	display: block;
}
.lb-album li > a{
	width: 150px;
	height: 150px;
	position: relative;
	padding: 10px;
	background: #f1d2c2;
	box-shadow: 1px 1px 2px #fff, 1px 1px 2px rgba(158,111,86,0.3) inset;
	border-radius: 4px;
}

The title for each thumbnail will be invisible and we’ll add a transitions for the opacity which will change to 1 once we hover over the thumbnail anchor. We’ll use a smooth radial gradient as background:

.lb-album li > a span{
	position: absolute;
	width: 150px;
	height: 150px;
	top: 10px;
	left: 10px;
	text-align: center;
	line-height: 150px;
	color: rgba(27,54,81,0.8);
	text-shadow: 0px 1px 1px rgba(255,255,255,0.6);
	font-size: 24px;
	opacity: 0;
	background: 
		radial-gradient(
			center, 
			ellipse cover, 
			rgba(255,255,255,0.56) 0%,
			rgba(241,210,194,1) 100%
		);
	transition: opacity 0.3s linear;
}
.lb-album li > a:hover span{
	opacity: 1;
}

The overlay will have the same radial gradient and we’ll set its position to fixed, with zero height and width:

.lb-overlay{
	width: 0px;
	height: 0px;
	position: fixed;
	overflow: hidden;
	left: 0px;
	top: 0px;
	padding: 0px;
	z-index: 99;
	text-align: center;
	background: 
		radial-gradient(
			center, 
			ellipse cover, 
			rgba(255,255,255,0.56) 0%,
			rgba(241,210,194,1) 100%
		);
}

Once we click on a thumbnail, we’ll cover the whole screen with the overlay, but first, let’s take a look at the children.

Let’s style the division for the main title and the description:

.lb-overlay > div{
	position: relative;
	color: rgba(27,54,81,0.8);
	width: 550px;
	height: 80px;
	margin: 40px auto 0px auto;
	text-shadow: 0px 1px 1px rgba(255,255,255,0.6);
}
.lb-overlay div h3,
.lb-overlay div p{
	padding: 0px 20px;
	width: 200px;
	height: 60px;
}
.lb-overlay div h3{
	font-size: 36px;
	float: left;
	text-align: right;
	border-right: 1px solid rgba(27,54,81,0.4);
}
.lb-overlay div h3 span,
.lb-overlay div p{
	font-size: 16px;
	font-family: Constantia, Palatino, serif;
	font-style: italic;
}
.lb-overlay div h3 span{
	display: block;
	line-height: 6px;
}
.lb-overlay div p{
	font-size: 14px;
	text-align: left;
	float: left;
	width: 260px;
}

We’ll position the link element for closing the lightbox absolutely above the image:

.lb-overlay a.lb-close{
	background: rgba(27,54,81,0.8);
	z-index: 1001;
	color: #fff;
	position: absolute;
	top: 43px;
	left: 50%;
	font-size: 15px;
	line-height: 26px;
	text-align: center;
	width: 50px;
	height: 23px;
	overflow: hidden;
	margin-left: -25px;
	opacity: 0;
	box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
}

The image will have a maximum height of 100%. That’s one way of making the image somewhat reponsive and nicely fittin into the viewport (i.e our overlay). We’ll also add a transition for the opacity level. Once we “open” a large image, the opacity will get animated. We’ll see later how we can use an animation for the image.

.lb-overlay img{
	max-height: 100%;
	position: relative;
	opacity: 0;
	box-shadow: 0px 2px 7px rgba(0,0,0,0.2);
	transition: opacity 0.5s linear;
}

Let’s style the navigation elements:

.lb-prev, .lb-next{
	text-indent: -9000px;
	position: absolute;
	top: -32px;
	width: 24px;
	height: 25px;
	left: 50%;
	opacity: 0.8;
}
.lb-prev:hover, .lb-next:hover{
	opacity: 1;
}
.lb-prev{
	margin-left: -30px;
	background: transparent url(../images/arrows.png) no-repeat top left;
}
.lb-next{
	margin-left: 6px;
	background: transparent url(../images/arrows.png) no-repeat top right;
}

CSS3Lightbox01

When we click on a thumbnail anchor, it will point to the respective large version of the image which is in the division with the class lb-overlay. So, in order to address this element we can use the pseudo class :target. We’ll add a padding to the overlay and “stretch it” over the whole viewport by setting the width and height to auto (it’s actually not needed explicitely) and set the right and bottom to 0px. Remember, we’ve already set the top and left before.

.lb-overlay:target {
	width: auto;
	height: auto;
	bottom: 0px;
	right: 0px;
	padding: 80px 100px 120px 100px;
}

Now we will also set the opacity of the image and the closing link to 1. The image will fade in, because we’ve set a transition:

.lb-overlay:target img,
.lb-overlay:target a.lb-close{
	opacity: 1;
}

And that’s all the style!
Let’s take a look at the two alternatives that we are using in demo 1 and demo 2.

In the first demo we make the image appear by using an animation that scales it up and increases it’s opacity value:

.lb-overlay:target img {
	animation: fadeInScale 1.2s ease-in-out;
}
@keyframes fadeInScale {
  0% { transform: scale(0.6); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

In the second demo we’ll create the opposite effect, i.e. scale the image down:

.lb-overlay:target img {
	animation: scaleDown 1.2s ease-in-out;
}
@-webkit-keyframes scaleDown {
  0% { transform: scale(10,10); opacity: 0; }
  100% { transform: scale(1,1); opacity: 1; }
}

Demos

You will see that each browser performs quite differently when it comes to the transitions/animations. Adjusting duration, timing functions and delays, one can make the effects smoother, i.e. you can change the timing for Firefox only by changing the -moz- properties.

And that’s it! I hope you enjoyed this tutorial and find it inspiring!

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 63

Comments are closed.
  1. Well done! Works very smooth in Chrome! (not in IE8.0, but that probably is because of the :target pseudo class, right?)

    2 suggestions:
    – instead of the tiny browse-arrows at the bottom (demo 3), would it be possible to place them on the left and right side of the image – on hover? That way you you don’t have to move up and down when images are re-sized?
    – clicking at the background (ie, the original page) will close the image (instead of the tiny close button at the top).

  2. Very nice animation, though, there is a slight problem with the way it works.
    1st back button hit : It closes the photo
    2nd back button hit : it opens the last one.
    So in theory, back button should work only in the page and not on the gallery it self.

  3. Thank you all for your wonderful feedback and your suggestions!

    @Rodrigo, you are right! The thumbnails were floating “right”, so the order was wrong 🙂 I fixed it now! Thanks a lot!

    Cheers, ML

  4. I really like being able to do things with just html and css.

    On this site: http://www.youbetternotstress.com/

    They are using lightbox effect but instead of going to a picture, they go to an html page. Would this also be possible to do with just html and css? I think this is one of the best sites I’ve ever seen but it’s looking so complex with all the additives needed to pull off the look.

  5. Excellent! The only little weak point is the back-button in the browser, which makes the last popup appear again…

  6. This is really awesome. Just something to be aware of, it is not really a problem, but the forward and backward buttons in the browser play through the lightboxes before leaving the page. so, let’s say someone goes to a page and looks at three images this way, if they press the back button in the browser to get back to the page they were at before that, they woud have to press the button four times. Like I said, not a problem, just something to be aware of.

  7. Awesome stuff , just checked with IE8 and IE9 not working can anyone Found Solution for it ??

  8. This is very nice demo, but in practice is useless.
    Standard jquery colorbox or fancybox is much better. First – this work only in super duper new browser. I am not talking here about IE6/7…
    Second – when you click on thums, and then you wont back to previous page, you must back by all clicking #
    But for idea ‘use only css’ – this is still nice demo.

  9. OMG … I could never be thinking that lightbox like this much smooth and slick can be possible with css.

    This is really awesome to have a lightbox with css3, this is really better than any jquery or mootools lighbox…!!

  10. I like you solution very much. I was trying to adapt it so the 150x 150 thumbnails would slide to the width of specific max-width media queries and stay centered like the top bar and header. The width of the lb-album is set to 900px. If I change it to 100%, the thumbnails slide but are not centered. I’ve been working on a solution for some hours now but not getting very far. Any suggestions on how to center these so they slide centered with the header?

  11. Thank you a for a great Javascript-free tutorial!

    I am having problems making it work on a mobile device, which in this case is an iPhone 3GS. My overlay doesn’t vertically fill the screen… It’s driving me nuts. I tried your demo on my phone and it’s all wonky, so I’m guessing this was not developed with mobile devices in mind. Do you, or anyone else, know how to get the overlay to fill the screen?

    Thanks!

    • I would suggest using position:absolute for the overlay (instead of position:fixed) as mobile devices don’t play well with fixed positioning. Then set the top and bottom to 0. As long as no parent containers of the overlay have relative positioning, this should fix the issue.

  12. Why the div tag inside .lb-overlay could keep its position 10px from the bottom when its parent div (.lb-overlay in this case) has a 120px padding-bottom, and both of them positioned in relative?

  13. Hello and thx for this great stuff !
    I’m having some problem with this lightbox. When I decide to publish a video (in an Iframe from Youtube) instead of a large version picture, it doesn’t want to stop when I click the X Close button.

    Is there a way I could fix it with CSS (i don’t think so !) ? Do I have to use some script ?

    Thx a lot for your answer (I hope it wil be one 😉

  14. This is awesome! I always had trouble using javascript to get the lightbox effect. Nice to know you can do this with CSS3

  15. Amazing!
    However, couldn’t make a gallery with just one thumbnail!
    Any way to do that?

    Thanks