withastro / astro

The web framework for content-driven websites. ⭐️ Star to support our work!
https://astro.build
Other
47.24k stars 2.51k forks source link

Navigation Links in Google Chrome iOS Are Replaced Upon Clicking Back, Losing All History #11919

Open alexookah opened 2 months ago

alexookah commented 2 months ago

Astro Info

Astro                    v4.15.1
Node                     v20.14.0
System                   macOS (x64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             @astrojs/sitemap
                         @astrojs/tailwind

If this issue only occurs in one browser, which browser is a problem?

iOS Chrome, iOS Edge

Describe the Bug

When navigating in Google Chrome on iOS, all links are being replaced after clicking back, causing the browsing history to disappear. I attempted to resolve the issue by using data-astro-history="push", but it didn't work.

Safari and Opera works fine. Only Chrome and Edge seems to have this issue. Not sure if this is an Astro (Transition) or Google Chrome-Edge issue.

Created also a Discord issue

I started with this theme: website I am working on.

What's the expected result?

Navigation history is kept and back button goes to previous page

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-rspsrp-qcdu3j?file=src%2Fpages%2Findex.astro

Participation

martrapp commented 2 months ago

As already discussed in the linked discord thread, I sadly have no equipment to debug this issue. Would appreciate if a Mac user could jump in or if someone knows an easy way for debugging iOS Chrome from Windows.

AndriiKobets commented 1 month ago

I will try to look deeper, but for now, it seems like 'onPopState' (transitions/router.js) event handler is not triggered when pressing Back button. However, when when calling history.back(); it works as expected.

afuggini commented 1 month ago

I am experiencing this as well.

I found that adding this script at the Layout level will apparently take care of the issue:

<script is:inline>
  document.addEventListener('click', (e) => {
    if (!/iPad|iPhone|iPod/.test(navigator.userAgent)) return false;
    const target = e.target;
    const link = target.closest('a');
    const shouldPushState = link && link.href && link.href.startsWith(window.location.origin) && !link.href.includes('#');
    if (!shouldPushState) return;
    history.pushState(null, '', link.href);
    window.dispatchEvent(new PopStateEvent('popstate'));
  });
</script>

You may adapt this to your needs while a more permanent solution is found.

grohart commented 3 days ago

Thank you @afuggini, it's working great!

I put your code into a svelte 5 component that I use for layout effects and just modified a line in order to only target Chrome and Edge for iOS (because it's working well with Safari)

<svelte:document
  onclick={ e => {
    if ( !/iPad|iPhone|iPod/.test( navigator.userAgent ) || !/CriOS|EdgiOS/.test( navigator.userAgent ) ) {
      return;
    }
    const target = e.target as HTMLElement;
    const link = target?.closest( 'a' );
    const shouldPushState = link && link.href && link.href.startsWith( window.location.origin ) && !link.href.includes( '#' );
    if ( !shouldPushState ) {
      return;
    }
    history.pushState( null, '', link.href );
    window.dispatchEvent( new PopStateEvent( 'popstate' ) );
  } }
/>
alexookah commented 3 days ago

anyone working on this for a proper solution to this issue?