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

[4.x]: Live preview doesn't retain scroll position when using scroll-behavior: smooth #14218

Closed
MoritzLost opened this issue Jan 26, 2024 · 15 comments
Assignees

Comments

@MoritzLost
Copy link
Contributor

MoritzLost commented Jan 26, 2024

What happened?

Description

By default, the live preview retains/restores the current scroll position when a field it's refreshed. However, this doesn't work if you use scroll-behavior: smooth on the HTML element:

html {
    @media (prefers-reduced-motion: no-preference) {
        scroll-behavior: smooth;
    }
}

This happens without using iframe resizer (useIframeResizer is set to false). Using iframe resizer fixes this in some cases, but unfortunately breaks the preview in other ways.

Steps to reproduce

  1. Include the CSS above in a template.
  2. Open the live preview for any entry and scroll down.
  3. Edit any field so that the live preview refreshed. The live preview will reset to the start of the page.

Expected behavior

Scroll position should be retained/restored even when using scroll-behavior: smooth. If that is unfeasible, the live preview could inject some CSS to overwrite the scroll-behavior property for the html element, that should be an acceptable workaround.

Craft CMS version

4.5.7

PHP version

8.2

Operating system and version

No response

Database type and version

No response

Image driver and version

No response

Installed plugins and versions

No response

@919Studios
Copy link

Not a huge deal but yeah, that feature no longer works for me as well & hasnt over the course of the last few updates in craft cms…

YOU MENTOINED A POSSIBLE SOLUTION: "the live preview could inject some CSS to overwrite the scroll-behavior property for the html element"

Maybe @brandonkelly can integrate a fix like that in future craft cms versions/updates to get the feature working again 👍🏻


Just tested this feature with the following:

Browser Version:
Firefox v121.0.1

Craft CMS version:
Craft Pro 4.6.1

PHP version:
8.2.8

@brandonkelly
Copy link
Member

Have you tried enabling the useIframeResizer config setting?

@MoritzLost
Copy link
Contributor Author

MoritzLost commented Feb 11, 2024

Have you tried enabling the useIframeResizer config setting?

@brandonkelly Yes, I've tried that. This fixes the issue, but also breaks the layout for some sites, so unfortunately it doesn't work for us.

@mmikkel mentioned on Discord that the live preview is capable of retaining the scroll position without using iframe resizer? If I remove the scroll-behaviour from our CSS it's working without using the iframe resizer. So probably it's something going wrong in whatever function is used to set the offset after the live preview refreshes?

@brandonkelly
Copy link
Member

Yeah we fetch the scrollTop and scrollLeft positions from the iframe right before replacing it with a new one.

if (sameHost && this.$iframe[0].contentWindow) {
this.scrollTop = $(
this.$iframe[0].contentWindow.document
).scrollTop();
this.scrollLeft = $(
this.$iframe[0].contentWindow.document
).scrollLeft();
}

I’m guessing that with smooth scrolling, those values aren’t getting reported correctly or something.

With useIframeResizer, the entire iframe is being scrolled within a container div on Craft’s end with overflow: auto, so it’s a lot more reliable.

@919Studios
Copy link

I may be missing something but…
• I added CRAFT_USE_IFRAME_RESIZER="1" to my .env file.
• Have added iframeResizer.contentWindow.min.js to my JS files & see its loading successfully.
• Checked my CSS for any scroll-behaviour / scroll-behavior, and dont see them there anywhere.

Still, the "scroll to where you are editing" craft feature is still not working for me.

thanks for your help!

Browser Version: Firefox 121.0.1
Craft CMS Version: Craft CMS PRO 4.6.1
PHP Version: 8.2.8

@brandonkelly
Copy link
Member

Still, the "scroll to where you are editing" craft feature is still not working for me.

There is no attempt to automatically scroll to where you’re editing. That would be a killer feature, but it would require some additional work in your templates, to give Craft some insight on where it should be scrolling to.

The only thing Craft attempts to do currently is retain your current scroll position, across preview refreshes.

@919Studios
Copy link

Craft used to do it. If i had a plain text field whose handle edited content at the bottom of my document, typing into that plain text field would jump the viewport down to that area of the screen. Dont you remember that feature?

@brandonkelly
Copy link
Member

I’m certain that we’ve never had that as a core feature. Maybe you had a plugin that did it?

@919Studios
Copy link

As you know, browser features can change drastically from version to version… The only thing I can think of is that there was something in the older versions of Firefox that made pages work like that. That would explain it ya know

@brandonkelly
Copy link
Member

Browsers would have no way of knowing they should scroll to some arbitrary point in an iframe on load.

@919Studios
Copy link

I really appreciate you helping out with this Brandon! I bet there was javascript that was making the CMS do that at the time and didnt even realize that - it was a few years ago when I was first learning Craft CMS… When I get some extra time, Ill fire up my old machine and that clients project to see how in the heck I was getting things to work that way. Thanks again for your help with this man - Craft 5 looks awesome by the way - cant wait to get crackin' on that! 😁

-Johnnie

@MoritzLost
Copy link
Contributor Author

@brandonkelly Sorry for the late reply!

Yeah we fetch the scrollTop and scrollLeft positions from the iframe right before replacing it with a new one.

if (sameHost && this.$iframe[0].contentWindow) {
this.scrollTop = $(
this.$iframe[0].contentWindow.document
).scrollTop();
this.scrollLeft = $(
this.$iframe[0].contentWindow.document
).scrollLeft();
}

I’m guessing that with smooth scrolling, those values aren’t getting reported correctly or something.

With useIframeResizer, the entire iframe is being scrolled within a container div on Craft’s end with overflow: auto, so it’s a lot more reliable.

I've had a look – the values are being reported correctly. A bit difficult to debug since I don't have a dev setup for Craft's CP, so I can only debug the compiled JS. Was able to find that piece of code in the compiled cp.js and put some debugging statements.

The values for scrollTop and scrollLeft are definitely correct right before this:

$($iframe[0].contentWindow.document).scrollTop(
  this.scrollTop
);

I think it might be a bug in jQuery. I tried replacing this with plain JavaScript:

$iframe[0].contentWindow.scrollTo(this.scrollLeft, this.scrollTop)

This works correctly even with smooth scroll enabled. There's a slight issue where the viewport shifts by ~50px (maybe due to the settings bar at the top of the preview window?). But way better than right now.

Could you give this fix a try? This issue is inconveniencing a couple of clients. Smooth-scroll is a default in many websites now, and as mentioned, iframe resizer breaks the layout in other ways :/

@brianjhanson
Copy link
Contributor

That looks to do the trick @MoritzLost! I've opened #14785 with this change.

@brandonkelly
Copy link
Member

Craft 4.8.9 and 5.0.4 are out with that fix! Thanks for the help.

@MoritzLost
Copy link
Contributor Author

Thanks @brandonkelly and @brianjhanson!

In Craft 4.8.9, the scroll position is now correctly restored. However, it's still a bit awkward with smooth scrolling, since every refresh of the live preview will trigger the scroll animation from the top of the page. I've worked around this by disabling smooth scroll in the live preview. Leaving this here in case anyone else has this issue.

<html {{ attr({
    class: [
        craft.app.request.getQueryParam('x-craft-live-preview') ? 'is-live-preview',
    ],
}) }}>
html {
    @media (prefers-reduced-motion: no-preference) {
        scroll-behavior: smooth;
    }

    &.is-live-preview {
        scroll-behavior: auto;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants