Edit in JSFiddle

/* Please note, this is not how I would write the CSS if I was just using 1 lightbox. This is for this specific unlikely scenario where 4 different lightboxes are used together. When using in production I would copy just one CSS section, remove the 'v[1-4]' class and change all `@extend %placeholder` for the real code */

%overlay {
  display: none;
  content: "";
  background-color: rgba(0, 0, 0, .5);
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
%loading-icon {
  display: none;
  content: "";
  position: fixed;
  top: 50%;
  left: 50%;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  z-index: 0;
  /* timer icon from https://materialdesignicons.com/icon/timer-sand (SIL Open Font License 1.1) */
  background: #333 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAwAAAAMADO7oxXAAAA2ElEQVRo3u2ZQQ4CIRAEwT/ynuXhm7QnDyIwIMjMxK7zhK2KsBoMgZD/JkoDAKAqGGPX8aEptwMGaCOegZLyTEh79Nfruf8EGKANA7TZHgAgo03WDg4VqTQYkStzqRw6EXAXz7wHIlryH2udCEiTEcPytTXUI8zJr4iYkf9GyJy8JFaZsyffi6jM2JRvRXQCtsq7/ymxBddbyPUhdv0adf1FtiKiHjG5bS4Al6mISfkXwxEnAkokeSnijeMBg/K9iKWA5Zu53fBmzhsM0MZ9AP8j04YBhBBdnpcx5ojPA/ruAAAAAElFTkSuQmCC) no-repeat center;
}
%positioning {
  position: fixed;
  top: 1em;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
}
%close-icon {
  content: "\00d7"; /* multiply sign */
  display: block;
  color: #fff;
  background-color: #000;
  position: absolute;
  top: 0;
  right: 1em;
  font-size: 2em;
  border-radius: 50%;
  font-weight: bold;
  line-height: 2;
  min-width: 2em;
  min-height: 2em;
  vertical-align: middle;
  text-align: center;
}
%bg-img {
  background: center / contain no-repeat;
  width: 100%;
  height: 100%;
}
%hide {
  display: none;
}
%show {
  display: block;
}
%hide-animatable {
  opacity: 0;
  transition: opacity .5s, max-width .5s;
  max-width: 0;
  max-height: 100%;
}
%show-animatable {
  opacity: 1;
  max-width: 100%;
}

/* additional styling, irrelevant for lightbox effect */
body {
  font-family: Arial, sans-serif;
  color: #333;
  background-color: #fff;
  max-width: 50em;
  margin: 0 auto;
  padding: .5em;
}
pre {
  overflow: auto;
}

.lightbox {
  margin-left: 1em;
  float: right;
  border: 3px solid #ccc;
  transition: border-color 1s;
}
.lightbox:hover {
  border-color: #999;
}


/* Lightbox #1
********************************************************************/

.lightbox.v1 {
  cursor: pointer;
  img {
    display: block;
  }

  &::before {
    @extend %overlay;
  }
  // big image
  img + img {
    @extend %positioning;
    @extend %hide-animatable;
  }
  
  &:active,
  &:focus {
    cursor: default;
    &::before {
      @extend %show; // overlay
    }
    img + img {
      @extend %show-animatable;
      cursor: pointer;
    }
  }
}

/* Lightbox #2
********************************************************************/

.lightbox.v2 {
  cursor: pointer;
  img {
    display: block;
  }

  &::before {
    @extend %overlay;
  }
  &::after {
    @extend %loading-icon;
  }
  // big image
  img + span {
    @extend %positioning;
    @extend %bg-img;
    @extend %hide;
  }
  img + span::before {
    @extend %close-icon;
  }
  
  &:active,
  &:focus {
    &::before,// overlay
    &::after, // loading-icon
    img + span { // big image
      @extend %show;
    }
    img + span {
      z-index: 2;
    }
  }
}

/* Lightbox #3
********************************************************************/

.lightbox.v3 {
  cursor: pointer;
  img {
    display: block;
  }

  &::before {
    @extend %overlay;
  }
  &::after {
    @extend %loading-icon;
  }
  // big image container
  img + div {
    @extend %positioning;
    @extend %hide-animatable;
  }
  // big image
  img + div > span {
    @extend %bg-img;
    @extend %hide;
  }
  img + div > span::before {
    @extend %close-icon;
  }
  
  &:active,
  &:focus {
    &::before, // overlay
    &::after, // loading-icon
    img + div > span { // big image
      @extend %show;
    }
    img + div { // big image container
      @extend %show-animatable;
      z-index: 2;
    }
  }
}

/* Lightbox #4
********************************************************************/

.lightbox.v4 {
  cursor: pointer;
  img {
    display: block;
  }

  &::before {
    @extend %overlay;
  }
  &::after {
    @extend %loading-icon;
  }
  // big image
  img + span {
    @extend %positioning;
    @extend %bg-img;
    @extend %hide-animatable;
  }
  img + span::before {
    @extend %close-icon;
  }
  
  &:active,
  &:focus {
    &::before, // overlay
    &::after { // loading-icon
      @extend %show; 
    }
    img + span {
      @extend %show-animatable;
      background-image: attr(data-img url);
      z-index: 2;
    }
  }
}
<h1>Pure CSS image lightboxes</h1>

<p>These are four different but similar pure CSS image lightbox techniques, using <code>:focus</code> (and <code>:active</code>), not <code>:target</code> or <code>:checked</code>. Read the <a href="http://blog.selfthinker.org/2016/05/13/pure-css-image-lightboxes/">accompanying blog post</a>.</p>

<h2>Pros</h2>
<ul>
  <li>No JavaScript (even works in Opera Mini… ish)</li>
  <li>Flexible (no specific IDs or widths/heights in the HTML or CSS necessary)</li>
  <li>Simple markup</li>
  <li>Keyboard-accessible</li>
  <li>Responsive</li>
  <li>Only loads big images when requested (except technique #1)</li>
</ul>

<h2>Cons</h2>
<ul>
  <li>Screenreaders might be confused by <code>tabindex</code></li>
  <li>The Esc key does not close the big image (but clicking anywhere or tabbing away does)</li>
  <li>Users have to relearn that navigating to or from an image does not work with right and left arrows but with Tab and Shift+Tab</li>
</ul>



<h2>Lightbox #1: Animated, pre-loads big images</h2>

<div class="lightbox v1" tabindex="0">
  <img src="https://unsplash.it/160/120?image=110" width="160" height="120" alt="" />
  <img src="https://unsplash.it/1024/768?image=110" alt="" tabindex="0" />
</div>

<p>This is the only usable version which is fully animated. The big disadvantage is that the big hidden image is loaded on page load. And lots of those can decrease page load time and lessen the user experience. But with not too many of them it is a way of pre-fetching the images and making the interaction smoother.</p>

<pre>
&lt;div class=&quot;lightbox&quot; tabindex=&quot;0&quot;&gt;
  &lt;img src=&quot;url_to_thumbnail&quot; alt=&quot;&quot; /&gt;
  &lt;img src=&quot;url_to_big_image&quot; alt=&quot;&quot; tabindex=&quot;0&quot; /&gt;
&lt;/div&gt;
</pre>



<h2>Lightbox #2: Not animated, lazy-loads big images</h2>

<div class="lightbox v2" tabindex="0">
  <img src="https://unsplash.it/160/120?image=78" width="160" height="120" alt="" />
  <span style="background-image: url(https://unsplash.it/1024/768?image=78)" tabindex="0"></span>
</div>

<p>The rest of the lightbox techniques only load the image when it is requested (via clicking or tapping the thumbnail or tabbing to it). That also means that loading the image can have a delay, which is why a loading icon is shown until then. This version is not animated.</p>

<pre>
&lt;div class=&quot;lightbox&quot; tabindex=&quot;0&quot;&gt;
  &lt;img src=&quot;url_to_thumbnail&quot; alt=&quot;&quot; /&gt;
  &lt;span style=&quot;background-image: url(url_to_big_image)&quot; tabindex=&quot;0&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
</pre>



<h2>Lightbox #3: Half-animated, lazy-loads big images</h2>

<div class="lightbox v3" tabindex="0">
  <img src="https://unsplash.it/160/120?image=76" width="160" height="120" alt="" />
  <div tabindex="0"><span style="background-image: url(https://unsplash.it/1024/768?image=76)"></span></div>
</div>

<p>This needs a bit more markup to allow the animation when the big image appears. But it does not provide an animation when the big image disappears again.</p>

<pre>
&lt;div class=&quot;lightbox&quot; tabindex=&quot;0&quot;&gt;
  &lt;img src=&quot;url_to_thumbnail&quot; alt=&quot;&quot; /&gt;
  &lt;div tabindex=&quot;0&quot;&gt;&lt;span style=&quot;background-image: url(url_to_big_image)&quot;&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
</pre>



<h2>Lightbox #4: Animated, lazy-loads images… and doesn't work</h2>

<div class="lightbox v4" tabindex="0">
  <img src="https://unsplash.it/160/120?image=249" width="160" height="120" alt="" />
  <span data-img="https://unsplash.it/1024/768?image=249" tabindex="0"></span>
</div>

<p>If only the <a href="https://developer.mozilla.org/en/docs/Web/CSS/attr">attr() CSS function</a> was properly supported by any browser. Then a fully-animated version which also lazy-loads images would be possible.</p>

<pre>
&lt;div class=&quot;lightbox&quot; tabindex=&quot;0&quot;&gt;
  &lt;img src=&quot;url_to_thumbnail&quot; alt=&quot;&quot; /&gt;
  &lt;span data-img=&quot;url_to_big_image&quot; tabindex=&quot;0&quot;&gt;&lt;/span&gt;
&lt;/div&gt;
</pre>