cms icon indicating copy to clipboard operation
cms copied to clipboard

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

Open MoritzLost opened this issue 1 year ago • 11 comments

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

MoritzLost avatar Jan 26 '24 15:01 MoritzLost

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

919Studios avatar Feb 10 '24 03:02 919Studios

Have you tried enabling the useIframeResizer config setting?

brandonkelly avatar Feb 11 '24 15:02 brandonkelly

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?

MoritzLost avatar Feb 11 '24 17:02 MoritzLost

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

https://github.com/craftcms/cms/blob/d86bd90e58db325bf24dc3d20bd6f426f097020f/src/web/assets/cp/src/js/Preview.js#L641-L649

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.

brandonkelly avatar Feb 11 '24 20:02 brandonkelly

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

919Studios avatar Feb 11 '24 20:02 919Studios

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.

brandonkelly avatar Feb 13 '24 18:02 brandonkelly

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?

919Studios avatar Feb 13 '24 19:02 919Studios

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

brandonkelly avatar Feb 14 '24 01:02 brandonkelly

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

919Studios avatar Feb 14 '24 02:02 919Studios

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

brandonkelly avatar Feb 15 '24 11:02 brandonkelly

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

919Studios avatar Feb 15 '24 19:02 919Studios

@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.

https://github.com/craftcms/cms/blob/d86bd90e58db325bf24dc3d20bd6f426f097020f/src/web/assets/cp/src/js/Preview.js#L641-L649

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 :/

MoritzLost avatar Apr 08 '24 15:04 MoritzLost

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

brianjhanson avatar Apr 10 '24 14:04 brianjhanson

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

brandonkelly avatar Apr 10 '24 22:04 brandonkelly

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;
    }
}

MoritzLost avatar Apr 17 '24 15:04 MoritzLost