-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Define that push/replaceState don't affect to :target handling #639
Comments
We might also want to think of some backwards compatible change to push/replaceState which allow target handling (and also hashchange events?). |
While I agree this should have worked, I also agree that since no browser has ever done it, and all major browsers are in agreement on it not working, that this change is the right course of action.
That would also be ideal. |
(@majido: smaug____ suggested in IRC that I ask you for feedback) a safe breaking change?From my understanding, the only reason to be wary of changing a behavior that every browser agrees on is the danger of breaking webpages, right? There's nothing intrinsically bad about changing behavior, the badness is that webpages that used to work may no longer work, which is intrinsically bad. Frankly, it seem far-fetched to me that fixing this would break a webpage. There are only two ways that could happen, that I can think of:
There are corpora available of stylesheets used on popular websites, right? We could analyze them to determine whether 1. is true, right? I doubt it's feasible to automatically determine whether 2. happens, but it also seems even less likely than 1., so supposing that 1. turns out in fact to never happen, could we make this change in Nightlies of each browser, and then maybe Betas, and see if anyone complains? I'd bet no one does, and the Web would simply be a better place. backwards-compatibly fixing thisOkay so if you wanna be a real hard-ass about this (or I'm wrong and we find a counterexample), how do authors ask browsers to recompute What if we made the fix a global, page-wide opt-in to minimize pain for web authors, like: history.recomputeTargetSelectors = true; Update: Looks like there's precedence for this kind of thing: Other options include:
h3:target-including-if-changed-by-pushState-this-should-probs-have-a-better-name {
background: yellow;
} Once upon a time we might've linked this to the next DOCTYPE version, but that's out of the question, right? |
In the Beginning, "Community" in the navbar on the homepage was a normal link, and clicking it would take you to the Community section and highlight the heading, and the browser Back button would take you back to your scroll position at the top of the page where the navbar was. Then I added smooth-scrolling so that when you click "Community" in the navbar it would smoothly scroll down to the Community heading, and highlight it. Problem: if you then hit the browser Back button, the heading highlight would vanish but you would stay in place, rather than the expected behavior of going back to the scroll position at the top of the page where you clicked on the navbar. Now I'm finally fixing that by doing history.pushState(): https://developer.mozilla.org/en-US/docs/Web/API/History_API (falling back to the old technique if unavailable) Of course the web platform sucks so we have to contend with: whatwg/html#639
I agree with @laughinghan and vote for fixing it early than carrying the weight of the bugs until the end of the web. |
Inspired by a discussion with smaug____ in IRC, I've found a good reason to believe that virtually no webpages would be broken by the "breaking" change of updating That means that the only way for a webapp to be broken by |
+1 for fixing this properly - it's very surprising behaviour. Conveniently @laughinghan's back/fwd find does provide a nice workaround for the current behaviour, which might be of interest to everybody else trying to actually use function pushHashAndFixTargetSelector(hash) {
history.pushState({}, "", hash);
// Do it again and go back immediately, to force :target to update.
history.pushState({}, "", hash);
history.back();
} This gives the expected result. Only side-effect (I think) is that the user's forward button is no longer disabled, although if they hit it, it won't break anything - it's the exact same URL. (Yes, this is a little nasty - we should fix it in the spec properly). More discussion on actually using this: https://medium.com/@pimterry/better-css-only-tabs-with-target-7886c88deb75. |
@pimterry Ha, thanks! Great workaround. Would be nice if pushState updated :target by default :( |
FYI @pimterry @robinbastien I believe you can avoid the odd side effect of the forward button being disabled by instead doing: function pushHashAndFixTargetSelector(hash) {
history.pushState({}, "", hash);
// go back and then come forward again immediately, to force :target to update.
history.back();
var onpopstate = window.onpopstate;
window.onpopstate = function() {
history.forward();
window.onpopstate = onpopstate;
};
} That's what I did in my original test http://output.jsbin.com/quludi |
When fixing this, please also consider what happens if you use In Firefox this will update the |
The CSS Selectors Level 4 spec now says:
This seems to me like it is saying that |
Yeah, the CSS Selectors spec is just wrong; it's unclear why they say that. They should fix it. The current HTML spec (which governs how :target behaves, not the CSS spec) already says that If you'd like a new pseudo-class that matches the current fragment, and doesn't match the target element (which is only updated in specific conditions), I opened w3c/csswg-drafts#6942 where developers can advocate for that. |
Ah, disappointing. As currently specced, I'm not really sure why it's valuable to not update |
How come that |
Btw regarding the workaround, instead of this chunk: var onpopstate = window.onpopstate;
window.onpopstate = function() {
history.forward();
window.onpopstate = onpopstate;
}; You can use window.addEventListener('popstate', () => { history.forward() }, { once: true } ) Which makes the same but without this onpopstate replacement magic trick. I still don't like this workaround though, I would prefer that |
Unfortunately the workaround isn't viable, since it triggers scroll to an anchored element upon navigation in Safari (works fine in Chrome, though). The whole reason of using Are there any methods to update the |
I found for iOS Safari (Atleast 17.2) that if you use an invalid fragment it doesn't scroll, so something like |
https://html.spec.whatwg.org/multipage/browsers.html#history-1
One could argue push/replaceState should affect to :target handling, but given that no browser seems to do that, we should probably just spec the current handling.
https://bugzilla.mozilla.org/show_bug.cgi?id=1246240
https://bugs.webkit.org/show_bug.cgi?id=83490
https://code.google.com/p/chromium/issues/detail?id=89165
The text was updated successfully, but these errors were encountered: