whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.14k stars 2.67k forks source link

intercepting same-document navigation caused by a user' direct address input in browser address bar #10258

Open Zhang-Junzhi opened 7 months ago

Zhang-Junzhi commented 7 months ago

In Chrome, navigate event listeners cannot intercept same-document navigation which is caused by a user' direct address input in browser address bar.

I read the spec and was unable to find any explicit statement made clear that a user' direct address input can be intercepted in a navigate event listener.

I think intercepting direct address input in the same document is a necessary feature for making a SPA look completely like a SPA. It's especially useful for a heavy-sharing SPA where someone shares some URL to others frequently.

Zhang-Junzhi commented 7 months ago

I think I had missed something before posting this issue: The spec explicitly says the navigate "will not fire for location bar-initiated navigations".

I totally understand firing a navigate event for cross-document navigation for location bar-initiated navigation is unacceptable for security reasons.

But it's not necessary to cut it all, I think it's reasonable to fire a navigate event for same-document navigation. Or is there any reason why it is necessary to disallow navigate events for same-document navigations?

domenic commented 7 months ago

navigate does fire for navigations where the user expresses the intent to make them same-document, by only changing the fragment portion of the URL.

navigate does not fire for navigations where the user expresses the intent to make them cross-document, by changing any other part of the URL.

This faithfulness to user intent is an important part of the user-facing security model.


Stepping back, I don't really understand your use case. In what scenarios are users hacking on non-fragment parts of the URL in their URL bar (already very rare), and somehow they expect this not to cause a page load?

You mention something about someone sharing a URL. Usually when one shares a URL to someone else, it's via something like a chat application. Clicking a link from a chat application into a web browser will always cause a full page load, as part of loading the browser. I don't understand what this has to do with modifying the contents of the URL bar.

Zhang-Junzhi commented 7 months ago

Consider if I am working on a multi-task page:

<section id="card 1" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 2" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 3" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 4" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 5" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<p>Bla bla bla. <span>Content 1.</span> Bla Bla Bla</p>

And then someone shares a page:

<section id="card 1" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 2" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 4" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 5" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 6" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 7" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<p>Bla bla bla. <span>Content 2.</span> Bla Bla Bla.</p>

I copy-paste and go to the shared page by the location bar, and then I see:

<section id="card 1" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 2" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 3" class="old collapsed with-close-btn floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 4" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 5" class="floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 6" class="highlighted-for-2s floated draggable-for-move-and-resize">Bla bla bla</section>
<section id="card 7" class="highlighted-for-2s floated draggable-for-move-and-resize">Bla bla bla</section>
<p>Bla bla bla. <del class="floated with-close-btn">Content 1.</del><ins class="this-extra-ins-will-be-stripped-when-del-is-closed">Content 2.</ins> Bla Bla Bla.</p>

This gives advantages over a complete page load:

  1. The view transition pops new cards, collapses old cards(with close a button), and keeps all other cards in the same coordinates and the same sizes, compared to an annoying page load which would cause me disoriented and have to refocus the contents;
  2. I have a chance to glance the differences of the two pages(and then close old ones);
  3. I have navigation history(If I click the shared link directly, a new tab will be opened, and I will lose the history that help me remember my navigation path).

Putting aside the "what will we benefit for firing navigate for location bar initiated navigations in the same document" quesiton, I would like to put the question to the opposite side: What will we benefit for not firing navigate for location bar initiated navigations in the same document? Will it reduce burden of browser implementation? I don't really think so. On the contrary, if it's required to not fire navigate for location bar initiated navigation in the same document, browser implementers will have an extra burden to selectively fire navigate events based on whether a same document navigation is location bar initiated.

This is my perspective, and I welcome any opinions from everyone.

domenic commented 7 months ago

What will we benefit for not firing navigate for location bar initiated navigations in the same document?

The benefit is the user-facing security model. Users know that when they change the non-fragment portion of a URL, they are going to do a new page load. Doing a new page load is important for users in various ways, from escaping abusive pages, to freeing up memory.

Violating this user expectation is not something we're currently interested in doing in Chrome without a compelling reason. The example use case you've provided is not very compelling: it seems extremely rare, and the advantages you list are very small.