react-images icon indicating copy to clipboard operation
react-images copied to clipboard

Image flicker effect on Safari

Open aldis-ameriks opened this issue 5 years ago • 16 comments

First of all, thank you for the amazing work on react-images. I've been happily using the library for some time now. I've just noticed that the v1 was released and decided to give it a go. However, came across what seemed to be a bug (or two separate bugs), that are at least perceivable on Safari.

Steps to reproduce the behaviour:

  1. Open http://jossmac.github.io/react-images on Safari
  2. Clicking on images other than the first one, sometimes yields a jumpy effect, where the very first image is rendered and then replaced by the clicked image. I could reproduce it consistently on Safari 12.0.2. I was not able to perceive the issue on Chrome, however, I could notice it slightly on Firefox, though, not nearly as noticeable as on Safari.
  3. When clearing browser cache in Safari (cmd+alt+e), reloading the page and immediately clicking on an imagine, sometimes yields a thumbnail view, which does not seem like the expected behaviour. I'm not sure if it's related with browser cache and unlike the jumpy image effect, this one I'm not able to reproduce consistently every time, but it does happen sometimes.

Expected behaviour:

  1. No jumpy effect when clicking an image
  2. No thumbnail view when clicking an image after clearing browser cache

Actual behavior:

  1. Jumpy effect when clicking an image
  2. Sometimes odd thumbnail view appears

In case someone is having difficulty reproducing the above mentioned issues, I've captured a screen recording, which is available here https://youtu.be/6YzoDd2fJao.

aldis-ameriks avatar Jun 19 '19 16:06 aldis-ameriks

I'm actually having the same issue, most of the time it recovers and doesn't get stuck in "film strip mode", but sometimes it does get stuck as in your video above. I believe the <Track> may be getting stuck on the viewport width instead of expanding beyond the viewport to it's full size. This causes all the images in the gallery to be forced to fit the viewport width.

Alba-C avatar Jun 21 '19 22:06 Alba-C

I think I have the same issue, especially if the images take some time to load and it’s the first time it loads them. Ex: Capture d’écran 2019-07-04 à 16 58 58

borisrorsvort avatar Jul 04 '19 15:07 borisrorsvort

@borisrorsvort i have the same issue, did you find a way to fix that?

thiagoneves avatar Aug 02 '19 03:08 thiagoneves

tl;dr; I think this related to the way how underlying library react-view-pager is calculating images transformation and to the fact that all of that is relying on ResizeObserver polyfill that doesn't officially support Safari.

I did some digging into this issue. It seems like this issue due to a problem in underlying package https://github.com/souporserious/react-view-pager

The Carousel component uses Track of react-view-pager to display Views (image representation) in a scrollable row see https://github.com/jossmac/react-images/blob/master/src/components/Carousel.js#L374

Track is relying on image size and count to calculate image zoom. Through a series of calls (Track component contains Pager component which also has an instance of a Track class, but not the component) we land in [Track.getStyles] (https://github.com/souporserious/react-view-pager/blob/master/src/Pager.js#L12) that calculates transformation style for a series of horizontally placed images as

this.pager.views.length / viewsToShow * 100 + '%';

This calculation happens only if trackSize is not false|null|undefined|empty string|NaN|0 here

I'm not sure against which of the cases authors of react-view-pager guard there. My guess is against 0 when trackSize set to auto (possible also from undefined?). Although when viewsToShow set to a number (like react-images does) trackSzie is not taken into account and transformation would work just fine in that case if not the guarding condition on line 19.

However, it works on Chrome. The problem goes dipper than that. Browsers load images in parallel and able to get their sizes before finish loading (jpeg stores image size among other meta information in the first 2 bytes of file header) react-view-pager is tracking image size change with the help of ResizeObserver Polyfill (https://github.com/que-etc/resize-observer-polyfill) Whenever images size updated (get known for the first time) ResizeObserver calls Pager.hydrate that would set track sizes and somehow triggers re-render and transformation recalculation in getStyles of react-view-pager discussed above.

It doesn't seem like used by react-view-pager version of the Polyfill has official support for Safari.

The flickering also exists in Chrome because of condition on line 19 of react-view-pager, but it negligible because Resize Observer updates sizes as soon as images start loading and transformation get recalculated.

I don't have a solution for this problem yet. But I'm looking for a workaround because I'm trying using react-images in mobile Safari with a large gallery of slowly loading photos.

Also huge thanks to react-images authors and contributors for your work on this library. ❤️

ssemakov avatar Aug 04 '19 19:08 ssemakov

@borisrorsvort i have the same issue, did you find a way to fix that?

No, I needed the fix fast and didn’t have time to investigate myself so I moved to https://github.com/frontend-collective/react-image-lightbox

borisrorsvort avatar Aug 13 '19 07:08 borisrorsvort

I'm having the same problem. Has anyone found a workaround or fix? I'd hate to move to a different module because react-images is working well other than this issue.

embryCODE avatar Sep 17 '19 15:09 embryCODE

Any updates on this issue? I'm facing the same issue too.

wesleywong avatar Sep 27 '19 09:09 wesleywong

I'm having the same film strip-problem.

@ssemakov did you find any workaround?

For me, it seems to be working with images loaded another origin than the site itself. Loading the same images from an external site works, at least for me.

I'll guess I'll have a look at react-image-lightbox, although I would rather stick with this package if there is some solution available.

ehannes avatar Jan 07 '20 14:01 ehannes

Hi Team,

I am facing exact same issue on iPhone 7 plus - safari when you click on any image strip of image appears. once user clicks on any one of the thumbnail it shows image in lightbox

anyone has quick fix for it ?

Thanks Pravin

pravinweb avatar Jan 13 '20 11:01 pravinweb

I don't suppose anyone was able to fix this bug were they?

AlmondoG avatar Feb 04 '20 22:02 AlmondoG

Unfortunately I don't use Apple devices so I can't test this and try to find the issue.

On Tue, 4 Feb 2020, 22:06 AlmondoG, [email protected] wrote:

I don't suppose anyone was able to fix this bug were they?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/jossmac/react-images/issues/287?email_source=notifications&email_token=ABYQJZRXUTZVFZ2NXYLX36LRBHRGPA5CNFSM4HZLOEGKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEKZLY7A#issuecomment-582139004, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABYQJZXQNS56FWPRJM4NEV3RBHRGPANCNFSM4HZLOEGA .

davwheat avatar Feb 04 '20 22:02 davwheat

@davwheat don't know how invested in this you are but Browserstack might be an alternative to not having any Apple devices

AlmondoG avatar Feb 06 '20 17:02 AlmondoG

Actually that's a great point - I do have a pro browserstack subscription with the GitHub student pack.

I'll try to look into it.

On Thu, 6 Feb 2020, 17:14 AlmondoG, [email protected] wrote:

@davwheat https://github.com/davwheat don't know how invested in this you are but Browserstack might be an alternative to not having any Apple devices

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jossmac/react-images/issues/287?email_source=notifications&email_token=ABYQJZTYTPCZISTERNUUIZTRBRAPTA5CNFSM4HZLOEGKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOELAAYFI#issuecomment-583011349, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABYQJZR5CNHHVAW6E7J6B6LRBRAPTANCNFSM4HZLOEGA .

davwheat avatar Feb 06 '20 17:02 davwheat

@davwheat any and all help greatly appreciated. I have some work done using React Images and it works great aside from this issue. If you are able to discover some sort of solution at all please don't hesitate to say so

AlmondoG avatar Feb 06 '20 18:02 AlmondoG

I ran into this recently, and I think I discovered part of the problem.

When the modal is loaded, each image is placed inside a View and these views have a width determined by the number of photos. For example, if there were 5 photos, each View would have a width of 20%.

These Views are inside of a Track. The track container should have a width set to 100% * numberOfPhotos (e.g. 500%), but it looks like the Safari bug is preventing this width from being set immediately.

You can test this out by looking for the track with your browser's developer tools (using the selector .react-images__track) and manually setting its width.

I don't have enough familiarity with the library and the Safari bug to know what the best fix is, but one workaround could be to allow us to pass a style prop to the Track component. That way we could set the width ourselves. We can already specify some props for the Track (see https://github.com/jossmac/react-images/blob/master/src/components/Carousel.js#L380), but any style given would be overwritten by the inline style set after the custom props are added.

tylermassey avatar Feb 06 '20 18:02 tylermassey

I also walked into this flickering problem on Safari and after some investigation I realised it just happens when I use a custom View component. E.g. This was what I had:

 components={{
                            View: ({ data }) => {
                                return _.map(images, (image, index) => {
                                    if (_.get(data, 'id') === index) {
                                        return (
                                            <StyledImage
                                                key={index}
                                                src={_.get(image, 'source')}
                                                alt="room"
                                                height={height}
                                                width={mainImgWidth}
                                            />
                                        );
                                    }
                                    return null;
                                });
                            },
                            FooterCount: () => {
                                return null;
                            },
                            FooterCaption: () => {
                                return null;
                            },
                        }}

But using just views={images} and no custom overwrite worked fine. I tried climbing into the code to see what causes this discrepancy, but I couldn't really find the issue. So I decided to not overwrite the default view component but just customising it via style prop, this is just my style prop where the view style is the applicable one, I passed my own custom height/width that changes responsively (own logic):

styles={{
                            container: (base) => ({
                                ...base,
                            }),
                            footer: () => ({
                                display: 'none',
                            }),
                            navigationPrev: navButtonStyles,
                            navigationNext: navButtonStyles,
                            view: (base) => ({
                                ...base,
                                paddingBottom: 20,
                                height,
                                overflow: 'hidden',
                                position: 'relative',
                                transition: 'filter 300ms',

                                '& > img': {
                                    position: 'absolute',
                                    left: 0,
                                    top: 0,
                                    borderRadius: 5,
                                    height,
                                    width: mainImgWidth,
                                },
                            }),
                        }}

This solved the flickering issue for me while being able to style my images to my liking. However, I realise this is more a hack than a fix since you won't be able to render your own custom image (or other) tags this way which sucks. But maybe this helps someone.

I really like this package so maybe when I have a bit more time I can try and see if I can dig deeper and find a true fix.

HanliTheron avatar Nov 20 '20 08:11 HanliTheron