I ran into a very interesting bug in a Rails legacy project involving Turbolinks. Here's a description of the bug:
Whenever a user clicked on a hamburger navigation icon a side nav would animate to open a list of nav links to click. Upon clicking this icon jQuery would add a class to the html
element on the page. Whenever a user clicked on one of those nav links Turbolinks would do what Turbolinks does: make an XHR request to the server to fetch the HTML required for the page and swap out the page's body tag for the body tag in the response. However, when Turbolinks drew the page with the new body tag from the server, the visitor could not scroll down the page -- the page appeared frozen.
When I removed the jQuery that added a CSS class to the html
element upon clicking the navigation, all the animation remind the same. I then went to click on one of the links, Turbolinks ran and now all of a sudden the page was unfrozen -- I could scroll up and down the page.
Why the original author applied CSS to the html
during a click event on the hamburger nav, I do not know. However, when I removed this jQuery behavior which added a CSS class to the html
element the page that Turbolinks drew was scrollable.
Does anyone know why adding a CSS class to the html
element broke the page that the Turbolinks fetched and drew? And does anyone know why the Turbolinks drawn page was scrollable when I removed the jQuery that added a CSS class to the html
element?
EDIT:
The CSS class that jQuery added to the html
element was this:
.-page-overflow-hidden {
overflow: hidden;
}
This is not a bug, this is specified on the Turbolinks readme https://github.com/turbolinks/turbolinks#navigating-with-turbolinks
During rendering, Turbolinks replaces the current
body
element outright and merges the contents of thehead
element. The JavaScript window and document objects, and the HTMLhtml
element, persist from one rendering to the next.
Check the bold part. The html
element persists from one page to the next, so, any class applied to it persists. Your code sets a overflow: hidden
CSS property, so it's still there after the new page renders.
I'd recommend to add something like this on your js file
document.addEventListener('turbolinks:before-render', function(event) {
document.getElementsByTagName('HTML')[0].classList.remove('-page-overflow-hidden');
})
That will listen to Turbolink's before-render
event (which triggers right after it starts rendering the new page) and you can remove that class from the first HTML element, just in case it's set.