Comment by friendzis

3 days ago

Nothing loaded from the web should be able to fiddle with any browser behavior, yet here we are.

The History API is pretty useful. It creates a lot of UX improvement opportunities when you're not polluting the stack with unnecessary state changes. It's also a great way to store state so that a user may bookmark or link something directly. It's straight up necessary for SPAs to behave how they should behave, where navigating back takes you back to the previous page.

This feels like a reasonable counter-measure.

  • Yeah but all of this is a symptom of a broader problem rather than reasons why the history API is useful.

    SPAs, for example, require so many hacks to work correctly that I often wonder to myself if they’re not really just a colossal mistake that the industry is too blinded to accept.

  • > It's also a great way to store state so that a user may bookmark or link something directly.

    Can you unpack this please? AFAIK history stack is not preserved in the URL, therefore it cannot be preserved in a bookmark or a shared link.

    • Probably referring to using pushState (part of the History API) to update the URL to a bookmarkable fragment URL, or even to a regular path leading to a created document.

      https://developer.mozilla.org/en-US/docs/Web/API/History/pus...

      > The new history entry's URL. Note that the browser won't attempt to load this URL after a call to pushState(), but it may attempt to load the URL later, for instance, after the user restarts the browser.

    • Sure. I'm not speaking about preserving the full history stack in the URL, just storing state. Apologies in advance if my explanation for what I mean is something you already understand.

      This can be as simple as having a single checkbox with a checked/unchecked state.

      when you load the webpage, the javascript can pull in the url parameters with URLSearchParams (https://developer.mozilla.org/en-US/docs/Web/API/URLSearchPa...). If the url parameter you set is set to 'on' then the checkbox, which is by default unchecked, can be set to on.

      You have your checkbox:

          <input type="checkbox" id="check">
      

      And then you have your javascript:

          const check = document.getElementById('check');
        
          // get state of checkbox from URL parameter
          check.checked = new URLSearchParams(location.search).get('state') === 'on';
          
          // add event listener to call history api to alter the URL state.
          check.onchange = () => { history.replaceState(null, '', check.checked ? '?state=on' : '?state=off'); };
      
      

      The history.replaceState() replaces the URL in your history with the one including the URL parameter, so if a user were to bookmark it, it would store that and reload it when they revisit the webpage.

      If I used history.pushState(), each time I clicked on the checkbox, a new item would be added to the stack. for a checkbox this is almost certainly a bad idea because your browser history is going to be polluted pretty quickly if you happen to click it multiple times.

      pushState can be useful when it matches the user expectations, though, like if it is an SPA and the user clicks on an internal link to another section of the site, they'd expect to be able to go back to the previous page, even though we're still on the same actual html page.

      So you would not be preserving the entire history stack. You can sort of do this by encoding state changes into another url parameter, but the behavior isn't entirely consistent between browsers. It also does require, as far as I know, an explicit action from the user for it to actually affect their navigation. So a website couldn't just add 1000 entries to the user's history on load without some explicit interaction on the web page.

      Once the user interacts, though, it does seem like it opens up a lot of opportunity to abuse it, intentionally or not. You can asynchronously push thousands of entries into the browser history without blocking interactivity of the site. you can even continue to push state to the URL from other inputs while doing so.

It should be opt-in per website, per feature, because IMO it can be quite useful in some cases. Like clicking back on a slide-show bringing you to the overview page, instead of only going back one slide

  • > clicking back on a slide-show bringing you to the overview page

    That behavior is expected in exactly one case (assuming slides, not the whole presentation, are modeled as a page each): If I navigated to that specific slide from the overview.

    In any other scenario, this behavior amounts to breaking my back button, and I'll probably never visit the site again if I have that choice.

  • Opt in features are a great way to increase user frustration and confusion. See the whole new geolocation API they had to make for browsers since people would perma-deny it reflexively and then complain that geolocation features weren't working.

    • That's a good point, though I'm not familiar with the (changes to the) geolocation API you mention. Do you have any recommendations for reading up on that development?

      1 reply →