Skip to content

Add zoomable images feature#3127

Merged
ehuss merged 7 commits into
rust-lang:masterfrom
GuillaumeGomez:zoom-in
Jul 3, 2026
Merged

Add zoomable images feature#3127
ehuss merged 7 commits into
rust-lang:masterfrom
GuillaumeGomez:zoom-in

Conversation

@GuillaumeGomez

@GuillaumeGomez GuillaumeGomez commented May 26, 2026

Copy link
Copy Markdown
Member

Fixes #2075.

The "zoomed-in" image looks like this:

image

The JS is only used to "zoom out" images with the "escape key", otherwise the feature works entirely without JS.

It works as follows: there is a (hidden) checkbox right before the image. The image itself is inside the label associated to the checkbox, meaning that when you click on the image, you switch the value of the checkbox. And thanks to :checked CSS selector, it changes the display of the zoomed out image.

To make it obvious that you can "zoom in"/"zoom out" on an image, I changed the cursor to look like a loop using the CSS cursor: zoom-in|zoom-out property.

I also realized that images had the alt attribute, but not the title one, so I added it while I was at it.

@GuillaumeGomez GuillaumeGomez requested a review from ehuss May 26, 2026 16:14
@GuillaumeGomez GuillaumeGomez mentioned this pull request May 26, 2026
@GuillaumeGomez GuillaumeGomez force-pushed the zoom-in branch 2 times, most recently from e172cff to 4d67425 Compare May 26, 2026 16:19
@rustbot rustbot added the S-waiting-on-review Status: waiting on a review label May 26, 2026
@GuillaumeGomez

Copy link
Copy Markdown
Member Author

Updated failing tests as well, ready for review. :)

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

ping @ehuss

@ehuss

ehuss commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Won't this break images that are links?

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

I think it would yes. Didn't think about that. If I only allow to zoom on non-link images, does it sound good to you?

@shenef

shenef commented Jun 8, 2026

Copy link
Copy Markdown

The description mentions the escape key for zooming back out, how would that work on a mobile device? Or does tapping it again toggle off the invisible checkbox?
I have a case where i currently use an image with a link to open a separate full-size version of the image. (740x638 -> 3712x3200)
So with this feature there would be no more need to do that.

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

The description mentions the escape key for zooming back out, how would that work on a mobile device? Or does tapping it again toggle off the invisible checkbox?

Tapping again will zoom-out.

@rustbot

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the zoom-in branch 2 times, most recently from bb61242 to 83f42f9 Compare June 8, 2026 19:40
@GuillaumeGomez

Copy link
Copy Markdown
Member Author

@ehuss Disabled the feature on images inside links and extended test to check it as well.

@ehuss ehuss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks!

I'm not going to block on it, but this doesn't seem to support the ability to trigger with the keyboard. Generally we try to ensure to follow accessibility guidelines as much as we can.

Just curious, was it intentional that you can still scroll when the image is zoomed in? (I'm not sure if I have a preference, just checking.)

I'm slightly uneasy not having a way to turn this off. I'm fine with starting without it, but if people have issues, we may need to add something. In particular, small images like icons probably don't need or want to be zoomed in this way.

View changes since this review

Comment thread crates/mdbook-html/src/html/tree.rs Outdated
Comment thread crates/mdbook-html/src/html/tree.rs Outdated
Comment on lines +578 to +579
} else {
img.insert_attr("title", alt.into());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why was this fallback to add the alt as the title added?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I mentioned it in my first comment:

I also realized that images had the alt attribute, but not the title one, so I added it while I was at it.

It's better for accessibility, and for other users, to have text when they hover an image without moving for a while.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think I would prefer to not do that. For example, MDN explicitly says:

avoid duplicating the alt attribute's value in a title attribute declared on the same image. Doing so may cause some screen readers to announce the same text twice, creating a confusing experience.

I also haven't seen other markdown renderers do something like this.

label.insert_attr("for", img_input_id.to_tendril());
self.push(Node::Element(label));

self.append(Node::Element(img.clone()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm a little concerned about this approach of using a duplicated <img> tag. Screen readers may have difficulty handling this. I think at a minimum it should have aria-hidden="true". I'm a bit uncomfortable with this approach in general, though I'm willing to give it a try.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think screen readers all handle display: none, so I think we're fine (although if we could test it, would be even better). However, won't aria-hidden=true be an issue when the image is zoomed-in?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I tried with my screen reader. It does seem to ignore the "display: none".

It's a little awkward now since the screen reader navigates to the checkbox (and says you are on a checkbox, and tells you the image alt), and then the image (and the alt and title). But I suppose it should be fine. We can adjust it if we get further feedback.

Comment thread crates/mdbook-html/src/html/tree.rs Outdated
Comment thread crates/mdbook-html/front-end/css/general.css Outdated
Comment thread crates/mdbook-html/front-end/js/book.js
Comment thread tests/gui/image-zoom.goml
call-function: ("check-image-zoomed-in", {})

// We click on the wrapper to "zoom out".
click: ".checkbox-label > img"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it intentional that this clicks on the image underneath the wrapper? That is, should this be something like ".image-wrapper > img" or ".image-wrapper" to simulate what the user would actually click on?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Well, they click on the image, but the image being part of the label, since there is no preventDefault() on the image, the event is propagated to the parent until the parent is the label which then handles the click event and stops its propagation. So it is how users will interact with it.

Comment thread crates/mdbook-html/src/html/tree.rs Outdated
@ehuss

ehuss commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Also, it's probably a good idea to include at least some note in the documentation that this exists. Perhaps on the Images section?

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

I'm not going to block on it, but this doesn't seem to support the ability to trigger with the keyboard. Generally we try to ensure to follow accessibility guidelines as much as we can.

I was sure I tested that, I'll double-check and add a regression test to ensure it works.

Just curious, was it intentional that you can still scroll when the image is zoomed in? (I'm not sure if I have a preference, just checking.)

I didn't consider it an issue but I can do it if you want as even with JS (it's required for that as I need to change a parent's style, so cannot be done with only CSS).

I'm slightly uneasy not having a way to turn this off. I'm fine with starting without it, but if people have issues, we may need to add something. In particular, small images like icons probably don't need or want to be zoomed in this way.

I can add a CLI option for that if you want? As for small images, if I want to know their size, I would need another dependency for that. Not sure it's worth it but again, your call.

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

I simplified the DOM generation: no need for an ID anymore. We can now make the zoom in feature work with the keyboard (still no JS, works with spacebar). Added a GUI test for it as well. And mentioned it in the mdbook guide.

I didn't add a new CLI option to disable it yet. Waiting for you to confirm if you want it or not.

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

Updated tests with HTML comparisons. :)

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

Fixed merge conflict.

@ehuss

ehuss commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

I can add a CLI option for that if you want?

No, I don't think it's necessary for now. Also, all of the options for rendering go in the config, not the CLI. So, for example, this would probably go in the [output.html] section.

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

Removed the title attribute.

Comment on lines -563 to -565
if !title.is_empty() {
img.insert_attr("title", title.into_tendril());
}

@ehuss ehuss Jul 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like this deleted the title attribute entirely. It should probably just keep the original code here.

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Arf. I think I messed up when fixing the merge conflict when I removed the commit. Fixing that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok it's back as it should. Sorry for the mess.

@GuillaumeGomez GuillaumeGomez force-pushed the zoom-in branch 2 times, most recently from 41c5578 to 5413eb8 Compare July 2, 2026 20:56
@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@rustbot

rustbot commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@GuillaumeGomez

Copy link
Copy Markdown
Member Author

Finally fixed my merge conflicts mess. ^^'

@ehuss ehuss left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@ehuss ehuss added this pull request to the merge queue Jul 3, 2026
Merged via the queue into rust-lang:master with commit 8b53f1b Jul 3, 2026
15 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: waiting on a review label Jul 3, 2026
@GuillaumeGomez GuillaumeGomez deleted the zoom-in branch July 3, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Zoomable Images

4 participants