CSS Lightbox with Text on Open

What CSS methods are available to display a modal? What are the pros and cons?

Requirement

My page will contain multiple identical siblings, each containing an image and some text.

On click, I want a lightbox to display the same elements that are on the page, including the image, as well as some elements which are hidden when the lightbox isn’t open.

Want to avoid repeating content in the HTML file.

Should work nice with a mobile device or desktop.

No bootstrap or other external libs.

Lightboxes

It seems that various CSS image lightboxes may be better solutions than any of the modal methods listed in this post. Lightboxes might not repeat image urls twice, and often support captions that are visible only when the image is expanded. i don’t need carousel or slideshow. Maybe i shouldn’t call this post “modal” at all?

So, haven’t found one that doesn’t repeat the image.

Target method

This method puts the modal content into a targeted div which is hidden when not active, using the :not(:target) pseudoclasses. It uses display: flex to display the modal, tho’ i dont quite understand how the flex helps. I don’t understand the relationship between the "modal" div and the "modal__window" div.

Here’s another target example. Not sure if it’s different in any essential way.

Checkbox method

This method uses the hidden checkbox hack. It uses the :checked state of the checkbox to show the modal. I’m curious about doing it with radio buttons, since we only want to allow one modal at a time. This method uses fig and figcaption, altho it seems fig, figcaption might be intended where the caption contains different information than the fig. It uses content: attr to avoid duplicate content in the HTML – not sure if that can work for image.

This method seems a variation on the checkbox method. Not sure if it differs in any essential way from the above.

Some very nice JS-free work here, apparently using radio buttons. My current favorite.

Accessible method

This method allows user to open the modal via keyboard. It’s said to be semantic. However, it appears to depend on JS, which i’d like to avoid if possible.

Dialog method

This one uses the dialog element. Can it be used without JS?

Multi image

This one I can’t tell how the hide/unhide process works. It appears to repeat the image url twice for every image, once for the page and once for the modal.

Multi image with text

This one strongly resembles what i’m after. It appears to list each image url just once. The modal contains the same image that appears on the page, plus additional text. I can’t tell how the show/hide is done. I found it on this page called “CSS Modal Windows”, but i see a bunch of JS.

Social media

No idea how this one works, but i see the same image on the page as in the modal, plus additional content in the modal only.

Other

Can any of the above methods be simplified or improved? Any other methods?

My demo with the checkbox only allows one modal at a time so the distinction doesn’t make sense to me. Stu’s version uses radio buttons but requires an extra radio button so that you can close it but does it allow for the background to be clicked to close the modal (although that could probably be added).

The target method is useful unless you have links or other content in the modal that are interactive because then you lose the :target and the modal disappears.

It uses js in an inline click handler which is not ideal.

It uses js again and copies the image source into a new image.

Usually though you would show a higher quality image than the original thumbnail but that does depend on what you want to accomplish. If you want dynamic content then js is required although you can get pretty close with css alone as you have seen.

1 Like

For my usage, it would be the same image, same size, same quality.

Unclear. So a pure CSS lightbox isn’t “dynamic”?

A pure css modal can only work with what’s available and can’t duplicate or insert extra content.

In my example you could show the image in the modal but then it will disappear from where it was. That won’t matter if you are hiding the page content when the modal is shown but in my example with the partially opaque background you can see what’s underneath.

It all depends on what you want to achieve as any of the methods you have shown are ok in the right circumstances (apart from the inline click handler example).

1 Like

Here’s another example that puts the original image in the modal also.

Note that in terms of accessibility the checkbox/radio hack and the :target method make keyboard navigation difficult. Although you can tab to a checkbox with the keyboard the user won’t know it’s a checkbox and if they press enter as you usually would to open a modal nothing will happen. Keyboard users generally know that checkboxes are activated with the spacebar by default but if the checkbox is hidden then they won’t know what to do. In would actually be better to keep the checkbox/radio visible in terms of accessibility.

There are always a number of things to consider so a ‘best’ answer is always subjective.

For modals I would consider that JS provides a more accessible solution as you can tab to the trigger elements and press enter which will be interpreted as a click.

1 Like

Image caching on same page

If the same image url is referenced twice, won’t the client use it’s own cache for the second reference on the same html page? Is there a way to force that? I understand there are some declarations for caching, but i don’t know if they would help in this scenario.

“Modal”

Is a lightbox a “modal”? In desktop programming, modal means you can’t click anything else until you close the modal. Some of the “modals” and lightboxes i posted above close when you click outside the modal.

“Interactive”

“Interactive” meaning, simple links are ok unless there’s a CSS :target rule which applies to them?

CSS vs JS

I’m intuitively partial to CSS-only methods, but not sure i can say why. What are some reasons a CSS-only method is preferable to a JS method? Ok, i found these:

CSS:

JS:

  • CSS may be inaccessible (but :focus selector may fix that)
  • If the item requires interaction, use JavaScript (but we have CSS selectors for interaction). https://gomakethings.com/when-to-use-css-vs.-javascript/
  • old browsers which don’t have CSS3 support. (but i made a decision not to support such browsers. Too much dev effort for a very small, shrinking user-group).

What are the downsides to inline click handlers?

Single image

You mean without stating the image url twice? I’m not opposed to the image disappearing from it’s original location. Seems kinda cool. :slight_smile: I imagine watching the image break free from it’s position on the page, and animated glide from it’s page position to it’s position on the modal.

Awesome! Your new solution is now my current choice. Can we animate the travel of the elements from their page position to their position on the modal? Which of your CSS rule hides the page when the modal is open? Does this solution push figure/caption a bit beyond it’s intended use?

Accessibility

Can we enable escape key to close the modal? I only see JS methods for the escape key.

It seems that, due to the border-color change when they tab to it, they will know it’s a hotspot of some kind, such as a simple link. So they will still know to hit the spacebar. Can we get hover behavior when tabbed to the element, maybe with :focus or :focus-visible? https://stackoverflow.com/a/45191208/209942

Unclear. Isn’t spacebar is the normal keyboard-click?

Yes if the same image is used twice on the page then the second or subsequent images are taken from cache. There is no overhead in repeating the same image.

They keep changing the terms but generally a modal is something that opens over other content and directs your attention to whatever is displayed. Usually you would have to dismiss the modal before you can continue with something else.

Whether or not clicking outside the element should close it is a UI question but often it makes it easier to use if you can click outside the element. However if you have content close to the inside edge of a modal and a user with poor motor control may click accidentally outside and close the modal before completing the task. As I said there never is a straight answer. :slight_smile:

If you have used :target to open a modal and then when you click any link in your modal the modal will close. This means that if in your modal you had a fragment identifier to other content in the modal the user would never see the other content because the modal would close. An element is only a target until its not.

That’s an age old question and the lines have become blurred in recent years with some of the new css properties.

Generally CSS is for presentation and JS is for behaviour.

If you can avoid js then yes it’s better to do without but not at the cost of complexity or bad accessibility. Of course you should ensure your page works if js is disabled which is why it should usually be added on afterwards as an enhancement. Sometimes though it’s not that easy to accomplish.

Css can handle the presentation and animation but very often you need that to happen in response to a behaviour. This can be accomplished by JS adding a class to an element to trigger the animation to start. Something that can’t often be achieved with css alone.

No css3 is css.

Css isn’t inaccessible as such but you do need to take care that keyboard users can use your page easily and generally that means highlighting elements using :focus so you can see where you have tabbed to.

Modern browsers have great support. You should not support a browser where the vendor no longer supports it. Old browsers are a security hazard and all the ransomware viruses targeted older browsers so you should encourage users to use an updated newer browser.

You can check support for new features on the caniuse site and using @supports you can build in fallbacks where needed. These days CSS is open ended in that you are always going to get new features so you won’t really have ccs4 or 5. Numbers are irrelevant.

They are javascript in your html.

Javascript belongs in a javascript file just as css belongs in the css file. Once you start inlining any of those then you are no longer separating the concerns and basically hard wiring your mark up. You may as well go back to font tags and the like :slight_smile:

Yes you need js for that and escape is not a key I would generally search for.

No, as I said before the general way that you action a link via the keyboard is to hit return (enter). No one knows that your checkbox hack is a checkbox because it is hidden. they would never think to click the spacebar. The spacebar is only used in form controls and not general links or actions. Enter is the key you want to work for this. If you try my example you will see that you can tab to the image (as I set the border on focus) and it will open the modal if you press the spacebar. Most users will not know to do that.

No, only for form elements. All links are actioned by enter. When you open a modal you are basically linking to a modal in essence.

I’ve quickly recoded my last demo to use JS so that you can see how much easier the keyboard behaviour is. You can tab to the element and then press enter and it will open and then you can tab to the close icon and press enter and it will close. All without using the mouse.

I’ve also use js to copy the image and its title into the new modal automatically so there is no duplicate content. This allows the page to remain nicely underneath undisturbed. I hate it when elements disappear and appear somewhere else and is a usability failure.

I haven’t dotted all the i’s as that was a quick recode but the general idea is sound.

1 Like

I’d like to see the image detach from the page and glide to it’s new position on the modal. For me, that would help the user conceptualize what’s happening. In my application, i think it’s appropriate and useful, and just plain fun. Can we animate that?

That might be awkward. I’ll have to have a think about that.

Back tomorrow with some thoughts :slight_smile:

Here is one way of using a <dialog> element with relatively simple code:

(The ‘Esc’ key works.)

2 Likes

Thx! But trying for pure CSS.

Target revis

i noticed on any webpage, spacebar will open a link. That’s a universal, right? If the image on page is a link (or looks and acts like a link), then won’t keyboard users know to hit the spacebar? Would the :target method excel here?

@PaulOB
I’ve also use js to copy the image and its title into the new modal automatically so there is no duplicate content.

Seems that if the movement between two positions is animated (from the page to the modal), then you’d be forced to do it with one image.

In my view there is no point at all striving for pure CSS. Of 509,314 visits to the UK Government’s home web page only 1113 definitely had JavaScript disabled (reference). Of these 1113 it is not clear how many were real people!. (For various possible reasons there were 4329 visits where it was not clear whether or not JavaScript was disabled in some way.)

If an extreme nerd has deliberately disabled JavaScript in their browser then they have to expect some limited functionality of web pages when they browse the internet.

There’s no point making life difficult for yourself and degrading the experience of visitors to your website just to cater for an extremely small number of people who have deliberately disabled JavaScript in their browser. Anyway you could use the <noscript> tag to cater for them.

I don’t believe using JavaScript introduces any perceptible delay. Of course it could be argued that all the extra HTML and CSS needed to avoid using JavaScript will slow down page load.

1 Like

Any stats on that?

You say in post #6 that:

I have a web page with a very large amount of JavaScript (over 4000 lines) but everything seems to work instantly (albeit on a tower PC).

In my CodePen above (post #11), the code within the JavaScript function is taking less than 2ms (on my PC)…

1 Like

I forgot to mention: seeking a grid or flex for the sibling items.

This almost does what i have in mind, but the transition isn’t working. I realize it’s because the position property is changing from static to fixed. So left and top can’t animate. If there was a way to keep the same position property in both states then we could animate left & top transition.

Some other ideas:

  • grid-column: 1 / -1 - Supposed to break out of grid and spread from first to last col. Not working for me. https://www.joshwcomeau.com/css/full-bleed/
  • width: 100%; box-sizing: border-box - I don’t know how this is supposed to work, but not breaking out of the grid. https://stackoverflow.com/a/5219611/209942
  • Change the parent of the content. Might require JS, or maybe :before and after pseudoclasses to wrap it in a different parent?

As I suspected its not straight forward for a couple of reasons.

Firstly you can’t move an element out of its positioning scheme without the rest of the page collapsing into the space you left unless you place every other item on the page into an exact position. You could transform or relatively position the element leaving the original space empty though. The problem with that is you can’t move the element to the middle as that requires auto positioning and you can’t animate auto positions and would rely on too many magic numbers.

In your example you aren’t just moving the image you are also moving the bio text and other things with the image. That means when the image does eventually get to the modal you have to make room for all the other stuff as well. If it was just an image being moved then it would be easier but to move something from an in-flow position into another context but remain also in-flow at that fixed position presents a number of problems.

I have a very rough version working in my JS demo as a proof of concept but it’s a bit of a mess at the moment as I am short on time today. However it may serve as a proof of concept for further development and clearly displays the things that need to be accomplished.


(View on codepen as it won;t work in that small window.)

JS most definitely has it’s uses. A wise dev will use all available tools, based on situation.

Where JS and CSS can do the same thing, i think it’s fair to call it a matter of preference. I’m partial to CSS when possible. I prefer declarative coding to procedural. And the reasons listed above. Also, i think JS has greater potential to cause a memory leak than CSS.