Scroll position when navigating between pages

I have found a similar problem in several web applications I’ve done in Elm. I think there are multiple strategies for dealing with this problem and wondered if anyone had any experience to share. The problem is the scroll bar position when navigating between “pages” within a single-page-application.

I think this mostly occurs when you have a shared ‘frame’, or ‘shell’, which is typically say a header bar, a menu, and perhaps a footer as well. So suppose you have an application that has a list of news article headlines, each of which you can click to read the entire article. You have a shell consisting of a header bar with a logo and maybe a profile button (login when not logged-in say), and a side menu bar. So your view function might look something like (obviously leaving out many details):

view : Model -> Html Msg
view model =
     let
          mainContent =
              case model.route of
                   Home ->
                        Html.ul
                             [ Attributes.class "headline-list" ]
                             (List.map viewHeadline model.articles)
                   Article articleId ->
                         let
                               article =
                                     getArticleSomehow ...
                         in
                         div
                                [ Attributes.class "article" ]
                                [ viewArticleTitle article.title
                                , viewArticleContent article.content
                                ]
     in
     div
         [ viewHeader
         , viewNav
         , mainContent
         ]

Now presumably each of the article headlines contain a link to the url for just that single article, and you do the usual thing to update the route upon a UrlChangeRequest. Similarly presumably there is way to go back from a whole article to the feed.

The problem is, if the headline list is long and you scroll down that list of headlines, when you click on a headline you are taken to the article page, but the scroll is remembered, so you are half way down the article when you should be at the top. In addition if you scroll up to the top of the article, and go ‘back’ (possibly via a back link in the application), then you are taken back to the list of headlines but the scroll position is wherever you were on the whole article page (perhaps at the very top).

I can think of a couple of solutions to this:

  1. On a route change, get the current viewport and remember it for the current route. For the new route you need to decide if you want to either set the scroll position to some remembered position, or reset it to the top.
  2. Have the ‘shell’ take up exactly 100% of the screen, and have the main-content part scrollable within that shell. I have tried this in the past and found it to be somewhat of a mine-field of corner-cases and different device/browser behaviours.
  3. Have the whole article page as an overlay and keep the main headline list underneath it. I’ve tried this approach before and it also has some device/browser behaviour differences, but fewer than case number 2.

So I guess I would like to hear of anyone’s experience with this issue. Any other solutions I haven’t thought of? Any advantages/disadvantages of any solution? I suspect the preferred solution will be largely dependent on the exact use-case, but would love to hear any related thoughts/comments.

2 Likes

I think that (1) is the most general solution, since what behaviour you’d want to have (scrolling back to top vs. remembering the location) depends on the system requirement.

Interestingly, in the past I’ve been created a system (artfacer) where you also have a long list of items (in this case: graphical artworks/photos), where the current scroll location is kept in the URL bar (there’s no view-switching in this app, but you’re supposed to be able to bookmark or share the URL to go back to the same location, even if there are newer items added to the list later) Example URL.
In that app, this was done by front-end and back-end working together to load the item indicated by the URL in the back-end, but as soon as the page is loaded, the closest newer items are loaded on above that one, with the scroll location being kept fixed.
So this system also uses a ‘remembered scroll position’, which in this case is not in pixels, but in ‘what item am I currently looking at’ so it can still remain valid after more items are added.

I thought maybe that might be an interesting example that you could compare to your own :man_shrugging:?

1 Like

Thanks that’s useful. I like the feature that you can bookmark a particular item but view surrounding items as well (rather just sending the person to a page with a single item on it). Very nice project.

In addition, you’ve made me think that what I really want to do is scroll to a particular item not a particular scroll position. Perhaps I can just encode the item in an anchor tag and parse that with the url and then scroll to that particular item. For other pages I probably just want to always scroll to the top.

1 Like

Different users can also have different expectations of how things should work. For example Discourse is using that “current scroll position in URL” and personally I find that really awful. Whenever I want to share a link to the thread I need to remember remove that scroll position from URL.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.