Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment: Add lightbox to Image block using directives #49621

Conversation

artemiomorales
Copy link
Contributor

@artemiomorales artemiomorales commented Apr 5, 2023

What?

This is part of the experiments section with the interactivity API in revising core blocks.
It uses directives from the Directives hydration system

Why?

It would enable native support for image lightboxes, a commonly used feature in many websites, without the use of jQuery or other external libraries.

How?

It adds directives on click to images, presenting a larger version of the image along with an overlay, which can be hidden with an additional click, by scrolling, or pressing the escape key.

Testing Instructions

  1. Add an image to a post
  2. Test enabling and disabling the lightbox using image's Advanced panel
  3. View the post
  4. Click on the image

Testing Instructions for Keyboard

  1. Tab to the image.
  2. Press Enter to open the lightbox.
  3. Test Tab or Shift + Tab — the lightbox should close and focus should go back to the image.
  4. Also test pressing Escape to close the lightbox.

Notes

  • This is an early implementation; the idea is for themes to be able to enable or disable the lightbox behavior, for child themes to be able to override that behavior, and for users to be able to toggle lightboxes for all images sitewide or at the block level.
  • This is part of a broader initiative to enable adding Interactivity API behaviors to components using the editor.
  • Currently, we can just toggle the lightbox for a particular image at the block level under the Advanced panel (see below)
  • The CSS implementation is not finalized. Ideally, I'd like to calculate the screen size and set the image to say 80% of the screen width, which will likely require some calculation outside of CSS. Is there a best practice for doing this?
  • I'm looking for feedback on the design and overall approach

Screenshots or screencast

Editor

image-lightbox-edit-mode.mp4

Frontend

image-lightbox-1080.mp4

@gziolo gziolo added [Block] Image Affects the Image Block [Feature] Interactivity API API to add frontend interactivity to blocks. [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible labels Apr 8, 2023
@artemiomorales artemiomorales added the Needs Design Feedback Needs general design feedback. label Apr 13, 2023
@jasmussen
Copy link
Contributor

This is really cool. Here's a GIF of the current state of the branch, showing the lightbox toggle in advanced, and how that looks when clicked on the frontend:

lightbox

Amazing work. Just works.

A couple of notes:

  • We probably want this toggle to be a block support, and sit in the styles tab of the image block inspector. Would not be a blocker for an initial version, but just thinking in terms of next steps.
  • It should probably be a toggle control instead of a checkbox. I think of toggles as equivalents to light switches: immediate effect, whereas a checkbox is usually paired with an "Apply" button.
  • The white scrim looks good. Outside of full-customization of this scrim color, could you default to using the site background color?
  • Can you make the scrim fade in and out as you open/close?
  • Speaking of, it's likely going to be the most useful as a global styles toggle. I wonder if for a first version, it could live in Global Styles > Blocks > Image only? That might let us get this out there, as adjacent features get hashed out.
  • I like that when you scroll, it "zooms out". I like that you used the zoom and zoom out cursors. I like that I can still right-click/open the source image in a new tab.

Note that if I also link the image to a destination, if I click the link, the lightbox invokes quickly, and then shortly after, the link is navigated to. We should probably just disable the lightbox entirely when an image is linked. This is likely worth doing also for the checkbox itself, or the design tool when we get a chance to upgrade it: it could be grayed out and have help-text that says something like "The lightbox behavior is disabled for linked images."

There's occasionally a "blink", or a flash of the image itself, as if it grows fully white for a nanosecond. It's hard to reproduce:

blink

When you click a small image that's a ways down on the page, it opens in place:
Screenshot 2023-04-14 at 11 03 04

Screenshot 2023-04-14 at 11 03 07

As shown in the example above, the image could be both bigger, and ideally centered in the currently visible viewport. Something like this:
Screenshot 2023-04-14 at 11 09 41

That's where it gets a little bit tricky, and will likely require some difficult JS to get just right. In the above, just for test purposes, I simply applied the following CSS to the image:

    cursor: zoom-out;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    padding: 2%;

That's not going to work too well, because it can't be animated in a performant way. But the principle is the same — show the image as big as the viewport is, (but bounded by max-resolution), and ideally centered in the viewport. What do you think?

@gziolo gziolo added the Needs Accessibility Feedback Need input from accessibility label Apr 14, 2023
@gziolo
Copy link
Member

gziolo commented Apr 14, 2023

It will be essential to ensure that all the accessibility requirements are met. I added the Need Accessibility Feedback label. I found an article by Graham Armfield that covers the specification for an accessible lightbox. I'm not sure if that is the best resource, but the list shared sounds reasonable:

I’ve tried to crystallise the accessibility requirements down into these few bullet points:

  1. Links that trigger lightbox:
    a. Must be able to get and show keyboard focus
    b. Must announce that they open an image in a lightbox – for screen readers and for sighted keyboard users
  2. When lightbox opens, focus must be placed somewhere sensible within the lightbox – suggest a Close link above or below picture.
  3. Wherever focus is within the lightbox it must be visible.
  4. The large image within the lightbox should have appropriate alt text added – especially if it is also a link to close the lightbox.
  5. Either of these:
    a. Tabbing beyond the last link in the lightbox or shift-tabbing before the first link should close the lightbox
    b. Tabbing should cycle within the actionable links within the lightbox until user clicks a close link.
  6. Whenever lightbox is closed, focus should be returned to whatever link/or image opened it in the first place
  7. If javascript is not present in the browser the page should behave appropriately.

That should be a good starting point for the discussion. It's very likely that the link that triggers the lightbox doesn't need to be visible until someone uses the assistive technologies. In effect, it could use the screen-reader-text CSS class that exists in WordPress core.

The Navigation block can also be used as a reference because when it's displayed as a small menu icon, it opens an accessible overlay with the close button.

@artemiomorales
Copy link
Contributor Author

@jasmussen Great, thanks for the feedback!

  • We probably want this toggle to be a block support, and sit in the styles tab of the image block inspector. Would not be a blocker for an initial version, but just thinking in terms of next steps.

Ok got it. This will likely come along with some more work on behaviors that I or someone else may take on — we can keep this in mind as we devise those next steps.

  • It should probably be a toggle control instead of a checkbox. I think of toggles as equivalents to light switches: immediate effect, whereas a checkbox is usually paired with an "Apply" button.
  • The white scrim looks good. Outside of full-customization of this scrim color, could you default to using the site background color?
  • Can you make the scrim fade in and out as you open/close?

Note that if I also link the image to a destination, if I click the link, the lightbox invokes quickly, and then shortly after, the link is navigated to. We should probably just disable the lightbox entirely when an image is linked. This is likely worth doing also for the checkbox itself, or the design tool when we get a chance to upgrade it: it could be grayed out and have help-text that says something like "The lightbox behavior is disabled for linked images."

There's occasionally a "blink", or a flash of the image itself, as if it grows fully white for a nanosecond. It's hard to reproduce:

Thanks for the feedback! I can make these changes and address these issues 👍

Speaking of, it's likely going to be the most useful as a global styles toggle. I wonder if for a first version, it could live in Global Styles > Blocks > Image only? That might let us get this out there, as adjacent features get hashed out.

This was something mentioned during a discussion with @luisherranz and @SantosGuillamot as well. I believe the end goal is to incorporate this into Global Styles just like you mention here, though a first pass would be to just allow users to enable the lightbox at the theme level with theme.json.

As shown in the example above, the image could be both bigger, and ideally centered in the currently visible viewport. Something like this...
That's where it gets a little bit tricky, and will likely require some difficult JS to get just right. In the above, just for test purposes, I simply applied the following CSS to the image:

cursor: zoom-out;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 2%;

That's not going to work too well, because it can't be animated in a performant way. But the principle is the same — show the image as big as the viewport is, (but bounded by max-resolution), and ideally centered in the viewport. What do you think?

I think this sounds great. A heads up that this lightbox behavior is based on the behavior used at Medium.com. I've set up a test article here, though you can also go to any Medium article and click on an image to see it. On our end, I believe I'll need to calculate the width of the screen to set the image scale.

One question I have: How do you propose we handle this behavior on mobile? While the Medium behavior works well on desktop, it's a bit wonky in mobile web:

Mobile

medium-mobile.mp4

Desktop

medium-desktop.mp4

@joedolson
Copy link
Contributor

A lightbox is basically just a modal dialog wearing a costume, and it should follow the same accessibility protocol that any modal needs to follow. If this was built on top of existing modal implementations, that would probably be a good plan.

@jasmussen
Copy link
Contributor

Thanks for the feedback! I can make these changes and address these issues 👍

Before you make too many changes to where the toggle lives, would be good to check with @SaxonF, who I think had a design putting this in the link dialog. Furthermore, on reflection I'm not sure it's valuable as a style option after all, since it's a bit more behavioral in nature — definitely a judgement call.

The main motivation to moving it to a block supports was to surface it in Global Styles, so that it could become a single "set it and forget it" toggle: make all images open a lightbox unless linked. Saxon what do you think? Are there use cases where you would want to disable this? Also CC: @jameskoster as you've thought about global settings like these. Is there a way to make it trivial for Artemio to move forward, but still in the future make it a global toggle? Maybe it can continue to live in "Advanced" for now?

@jameskoster
Copy link
Contributor

I can't get this working for some reason. I see the "Lightbox" checkbox in the Advanced panel, but toggling it on does nothing on the frontend. Tried adding/removing links in the link control – no dice 🤔

who I think had a design putting this in the link dialog

This seems sensible to me. Otherwise it's not really clear which behaviour would take precedence if you were to enable lightbox and add a link (either to media file or attachment page). On that note, it may make sense to see this option only when a link to the media file is added?

I don't have a strong feeling about the global implementation, but on the whole it feels like more of a contextual affordance, similar to making a link open in a new tab. I'd probably lean more towards a user preference for choosing the default behaviour when inserting images, rather than a global setting that gets unilaterally applied across the site.

@jasmussen
Copy link
Contributor

My main concern with adding it to the link dialog is that if I wanted to retroactivelly enable it on every image on my site with thousands of posts, wouldn't I have to edit them all?

@jameskoster
Copy link
Contributor

Yes, that's the trade-off. It feels like a separate thing to me though, and could be handled in a plugin.

If we did make this a global style property, what would happen if an image is set to link to the attachment page, and lightbox is true?

@jasmussen
Copy link
Contributor

If we did make this a global style property, what would happen if an image is set to link to the attachment page, and lightbox is true?

If an image has any kind of clickable link, my take is the lightbox should just not fire ever. So I could see a single toggle "show lightbox for images" somewhere, and then if an image is linked, it just won't fire there.

@jameskoster
Copy link
Contributor

That sounds a bit confusing to me, especially as a 'style' property. 🤔

@jasmussen
Copy link
Contributor

Yeah, style may not be the best place for it. That said, lightbox for only unlinked images seems to be the industry standard as far as my experience goes. Have you seen otherwise?

@jameskoster
Copy link
Contributor

Some members of the design team spoke about this recently in a huddle.

The global element gets quite tricky, and probably needs more design. Is it a site setting, if so where does that live? Is it part of global styles, and if so how do we make the interactions with link control feel intuitive? How do we enable local overrides at different levels (page / template / pattern / block)?

With all the said, the best course of action may be to design a really good UI for the most atomic scenario, IE a single image block, and extrapolate out from there when we've had more time to consider the global scope. What do y'all think?

@beafialho
Copy link

Has it been considered, instead of a zoom in motion, which in my opinion can be a bit too much, something like this?

image_effect.mp4
image_effect_2.mp4

And better yet, the possibility to define the animation and background color? 🙂

@artemiomorales
Copy link
Contributor Author

Has it been considered, instead of a zoom in motion, which in my opinion can be a bit too much, something like this?

I like this approach better. It's much more straightforward to implement and, as I'm looking at the code, I think it would be challenging to get the zoom to animate consistently across all WordPress sites.

@Poliuk
Copy link

Poliuk commented Apr 18, 2023

I also prefer Bea's animation 😄

the possibility to define the animation and background color? 🙂

That's a great question, and I think we haven't thought about it. I guess that if we add a setting to customize
the background and/or the animation, that setting should live inside some sort of advanced settings for each behavior, and they should be hidden by default.

I would suggest leaving that for a second phase. Once we have the first version polished, we can start thinking about adding support for customization and adding some more animations.

@jasmussen
Copy link
Contributor

That's a great question, and I think we haven't thought about it. I guess that if we add a setting to customize
the background and/or the animation, that setting should live inside some sort of advanced settings for each behavior, and they should be hidden by default.

One thing that might thread the needle is to use the same scrim color as the site background color, at least for the initial version. That takes care of dark or light themes at least.

@artemiomorales
Copy link
Contributor Author

I can't get this working for some reason. I see the "Lightbox" checkbox in the Advanced panel, but toggling it on does nothing on the frontend. Tried adding/removing links in the link control – no dice 🤔

@jameskoster Do you have the block hydration experiments plugin for the Interactivity API enabled by chance? If so, that may be overriding the customizations in this PR and preventing you from seeing the changes.

@artemiomorales
Copy link
Contributor Author

I pushed up a change to the animation so that it fades instead of zooming:

lightbox-fader.mp4

Next will look at accessibility while discussion on the UI continues.

@richtabor
Copy link
Member

I pushed up a change to the animation so that it fades instead of zooming

I prefer the zooming, though if the consensus is to fade that's fine. 🤷‍♂️

@richtabor
Copy link
Member

While testing today I noticed the front-end admin bar disappearing if the block/control is present:

CleanShot.2023-04-19.at.17.04.15.mp4

@michalczaplinski michalczaplinski mentioned this pull request Apr 21, 2023
@artemiomorales
Copy link
Contributor Author

I just pushed a commit that adds accessibility.

lightbox-accessibility.mp4
  1. When opening the image using the keyboard, focus should go to the Close button.
  2. Pressing escape or tabbing outside of the lightbox should close it.
  3. Focus should revert the image.

I tested with a screen reader, and I think it provides ezough detail but I'm not sure — would appreciate a second pair of eyes on that 🙏

Next will work on the admin bar bug and the dynamic scrim color.

@artemiomorales artemiomorales force-pushed the experiment/image-with-interactivity-api branch from b20351a to 58b0ef5 Compare May 5, 2023 05:25
Comment on lines +6 to +8
const raf = window.requestAnimationFrame;
// Until useSignalEffects is fixed: https://github.com/preactjs/signals/issues/228
const tick = () => new Promise( ( r ) => raf( () => raf( r ) ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that this pull request has been merged, this workaround shouldn't be necessary. Could you please try merging the add-interactivity-runtime branch and check if everything works as expected without using await tick()?

@@ -111,6 +111,7 @@ export function ImageEdit( {
width,
height,
sizeSlug,
enableLightbox = true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure but, shouldn't we define the default value in the block.json instead of here? Something like:

"enableLightbox": {
    "type": "boolean",
    "default": true
}

@gziolo gziolo force-pushed the add-interactivity-runtime branch from 06cdbd9 to 0cdab08 Compare May 5, 2023 08:42
@DAreRodz DAreRodz deleted the branch WordPress:add-interactivity-runtime May 5, 2023 09:39
@DAreRodz DAreRodz closed this May 5, 2023
@artemiomorales
Copy link
Contributor Author

Looks like this was closed when the base branch was merged; reopening now.

@gziolo
Copy link
Member

gziolo commented May 5, 2023

@artemiomorales, maybe try to rebase with trunk in your fork. There is no option to reopen PR at the moment. However, I see that the branch is still there 🤷🏻

@artemiomorales
Copy link
Contributor Author

Hi all, it appears we'll be unable to recuperate this pull request, so I've opened a new one here. Let's continue the conversation there. Thanks!

@artemiomorales
Copy link
Contributor Author

Hi all, here I'm giving a call for feedback as I've just pushed a batch of changes to the new pull request. The admin UI will change slightly when it's synced with WIP: UI Behavior, but other than that, I believe this PR is done.

Would be great to hear feedback on any of the decisions or revisions made 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Image Affects the Image Block [Feature] Interactivity API API to add frontend interactivity to blocks. Needs Accessibility Feedback Need input from accessibility Needs Design Feedback Needs general design feedback. [Type] Technical Prototype Offers a technical exploration into an idea as an example of what's possible
Projects
None yet
Development

Successfully merging this pull request may close these issues.