skip to Main Content

I’m working on a website where I only have control over (part of) the CSS code. I can’t add JavaScript code, and I also can’t change the HTML of webpages (because it comes from a Markdown compiler, and although Markdown supports inserting HTML tags, the content is written without them to keep the HTML abstracted).

Some webpages have images. These appear as plain (generated) <img> tags. I want to allow the user to "click to enlarge" these images. This functionality is apparently called a lightbox.

So, I want to support this for all these plain <img> tags in pure CSS and without adding extra HTML. I’ve found many solutions, but none satisfy this specification:

  • A lot of them use jQuery, e.g. all of these examples. A lot of what I’ve found is actually meant for galleries, like this one which uses JavaScript. Same for this entire library.
  • This thread just enlarges the image on hovering, rather than isolating it. This thread doesn’t require any extra HTML, but needs JavaScript. This thread is the same. This thread has a similar title to mine, but is actually completely different from what I want. This thread is about swapping images, and the proposed solution is to use an <input> tag, which I can’t.
  • The best one I’ve found is this Codepen, but it requires an <a> anchor tag around each <img> tag and apparently an additional pair of tags for the lightbox itself. The reason is that the <a> tag can change the fragment of the URL, and subsequently CSS can detect that change using :target. Same for this website.

I don’t need any gallery functionality with buttons. I literally just need any <img> tag to be clickable so it appears (perhaps with a zoom transition) in the center of the screen with a dimmed background, and clicking anywhere restores the page to normal.


Edit: Although some of the above threads don’t provide any code in the question themselves and I described the givens on my end (which is just <img src="..."/>), here is a minimised version of that last Codepen:

* body {
    background-color: white;
} 

.container {
    width: 100%;
    height: 100%;
}

.trans {
    transition: all 1s ease;
    -moz-transition: all 1s ease;
    -ms-transition: all 1s ease;
    -o-transition: all 1s ease;
    -webkit-transition: all 1s ease;
}

.top {
    display: flex;
    width: 80vw;
    height: 80vh;
    margin-top: 10vh;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 10vh;
}

.top ul {
    list-style: none;
    width: 100%;
    height: 100%;
    z-index: 1;
    box-sizing: border-box;
}

.top ul li {
    position: relative;
    float: left;
    width: 25%;
    height: 25%;
    overflow: hidden;
}

.top ul li::before {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #000;
    content: '';
    color: white;
    opacity: 0.4;
    text-align: center;
    box-sizing: border-box;
    pointer-events: none;
    transition: all 0.5s ease;
    -moz-transition: all 0.5s ease;
    -ms-transition: all 0.5s ease;
    -o-transition: all 0.5s ease;
    -webkit-transition: all 0.5s ease;
}

.top ul li:hover::before {
    opacity: 0;
    background-color: rgba(0,0,0,0.90);
}

.top ul li img {
    width: 100%;
    height: auto;
    overflow: hidden;
}

.lightbox {
    position: fixed;
    width: 100%;
    height: 100%;
    text-align: center;
    top: 0;
    left: 0;
    background-color: rgba(0,0,0,0.75);
    z-index: 999;
    opacity: 0;
    pointer-events: none;
}

.lightbox img {
    max-width: 90%;
    max-height: 80%;
    position: relative;
    top: -100%;
    /* Transition */
    transition: all 1s ease;
    -moz-transition: all 1s ease;
    -ms-transition: all 1s ease;
    -o-transition: all 1s ease;
    -webkit-transition: all 1s ease;
}

.lightbox:target {
    outline: none;
    top: 0;
    opacity: 1;
    pointer-events: auto;
    transition: all 1.2s ease;
    -moz-transition: all 1.2s ease;
    -ms-transition: all 1.2s ease;
    -o-transition: all 1.2s ease;
    -webkit-transition: all 1.2s ease;
}
.lightbox:target img {
    top: 0;
    top: 50%;
    transform: translateY(-50%);
    -moz-transform: translateY(-50%);
    -ms-transform: translateY(-50%);
    -o-transform: translateY(-50%);
    -webkit-transform: translateY(-50%);
}
<div class="container">
    <div class="top">
        <ul>
            <li><a href="#img_1"><img src="https://image.freepik.com/free-photo/road-curve-landscape_426-19324358.jpg"></a></li>
        </ul>
        <a href="#_1" class="lightbox trans" id="img_1"><img src="https://image.freepik.com/free-photo/road-curve-landscape_426-19324358.jpg"></a>
    </div>
</div>

2

Answers


  1. You don’t want to modify the DOM, and want to handle clicks, CSS simply can’t do that, it will just be hacks with :target or :active.

    img { width: 5em}
    img:active { width: unset}
    <img src="https://image.freepik.com/free-photo/road-curve-landscape_426-19324358.jpg">

    You have to either use JavaScript, or modify the DOM to use the details element, who has an open state.


    Click to enlarge (bigger image, center it on the screen, make the rest
    of the page darker). Click again to do the same but in reverse.

    As stated in the comment, here is a way to achieve this click/close effect with only HTML/CSS, but for that we have to use the details element.

    .popup > p {
        padding: 1em;
        margin: 0;
        display: flex;
        flex-direction: column;
    }
    .popup summary {
        padding: 1rem 0.5rem;
        cursor: pointer;
        overflow: auto
    }
    .popup summary > img {
        width:2em
    }
    .popup[open] summary > img {
        display: none
    }
    .popup[open] img {
        width: 90vw
    }
    .popup[open] summary {
        background: black;
        padding: 0.5rem;
    }
    .popup[open] {
        position: fixed;
        outline: 5000px #00000090 solid;
        border: 5px red solid;
        border-radius: 0.5rem;
        z-index: 1;
        max-height: 90vh;
        overflow-y: auto;
        overflow-x: hidden
    }
    .popup[open] summary::after {
        content: '❌';
        float: right;
    }
    <details class="popup">
      <summary><img src="https://image.freepik.com/free-photo/road-curve-landscape_426-19324358.jpg"></summary>
        <p>
          <img src="https://image.freepik.com/free-photo/road-curve-landscape_426-19324358.jpg">
        </p>
    </details>
    Login or Signup to reply.
  2. If you add tabindex="0" to the <img>, you can apply :focus:

    img {
      cursor: pointer;
    }
    
    img:focus {
      --offset: 20px;
      position: fixed;
      inset: var(--offset);
      object-fit: cover;
      width: calc(100dvw - 2 * var(--offset));
      height: calc(100dvh - 2 * var(--offset));
      box-shadow: 0 0 0 var(--offset) rgba(0, 0, 0, .6);
      z-index: 666;
      cursor: unset;
    }
    
    div {
      display: inline-flex;
    }
    
    div:has(img:focus) {
      height: 100px; /* same height of image - just jump content prevent */
    }
    <div>
      <img src="https://image.freepik.com/free-photo/road-curve-landscape_426-19324358.jpg" height="100" tabindex="0">
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search