URL: https://www.pressurecookrecipes.com/instant-pot-spaghetti-sauce/
Browser / Version: Safari 15+
Operating System: iOS 15+
Tested Another Browser: Yes Firefox
Problem type: Something else
Description: Page scrolls to anchor when updating a style element via ECMAScript and a link element was dynamically added on DOMContentReady
Steps to Reproduce:
The page provided (https://jrivera-projects.s3.amazonaws.com/safari-bug/index.html) has code that causes the issue and is interactive. This is a minimal test case but we have seen the problem occurring on several real world sites. One of them is: https://www.pressurecookrecipes.com/instant-pot-mushroom-risotto/#recipe where if you scroll up to the top from the recipe it'll jump back down to the recipe.
From the test case linked above: Click on "Go to element #foo" to scroll the page down to the #foo element. Then manually scroll back up here and click on the "Will it jump?" button to see the page scroll back to the #foo element. That scrolling is the issue - the page should NOT scroll. The button here is simply modify a <style> element. There are three seemingly unrelated preconditions that, when present on a page together, trigger this behavior:
PRECONDITION 1: Anchors The first is the presence of an anchor or "fragment identifier" in the URL. The fragment identifier must reference, by id, one of the elements on the page.
PRECONDITION 2: Dynamically Inserted Link Tag The second piece of the puzzle is that we need to dynamically add a element to the DOM. In order to trigger this issue, appending of the element must happen either via the "DOMContentLoaded" event or in the "readystatechange" event when document.readyState === 'interactive'. If the is added when document.readyState === 'complete', there will be NO jump. The contents of the file referenced by the href attribute don't matter. As seen in the demo here, the file could even be a 404 and the issue will manifest. Only if the "href" attribute is omitted will the issue not occur. <script type='text/javascript'> // document.addEventListener('DOMContentLoaded', () => { document.addEventListener('readystatechange', () => { if (document.readyState !== 'interactive') { return; } const link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.media = 'all'; link.property = 'stylesheet'; link.href = 'not-even-a-file.css'; document.body.appendChild(link); }); </script>
PRECONDITION 3: Dynamically Updating <Style> Tag For the final part, we simply construct a <style> element with document.createElement('style'); and add some CSS to it as a child "textNode". The actual CSS properties we specify don't seem to matter. I tested with font-size, color, and width but for this demo I leave any style properties empty. The CSS selector also does not need to match any element that is actually in the DOM! Each time the <style> element is updated, the page will jump to the element whose id is in the fragment. <script type='text/javascript'> const head = document.head || document.getElementsByTagName("head")[0]; const styleElement = document.createElement('style'); styleElement.type = "text/css"; head.appendChild(styleElement); const jumpBtn = document.querySelector('#jump'); jumpBtn.addEventListener('click', () => { const css = '#matches-nothing-in-dom {}'; const cssNode = document.createTextNode(css); const childNodes = styleElement.childNodes; const child = childNodes[0]; if (child) { styleElement.replaceChild(cssNode, child); } else { styleElement.appendChild(cssNode); } }); </script>
https://bugs.webkit.org/show_bug.cgi?id=244895
Browser Configuration
From webcompat.com with ❤️
URL: https://www.pressurecookrecipes.com/instant-pot-spaghetti-sauce/
Browser / Version: Safari 15+
Operating System: iOS 15+
Tested Another Browser: Yes Firefox
Problem type: Something else
Description: Page scrolls to anchor when updating a style element via ECMAScript and a link element was dynamically added on DOMContentReady
Steps to Reproduce:
The page provided (https://jrivera-projects.s3.amazonaws.com/safari-bug/index.html) has code that causes the issue and is interactive. This is a minimal test case but we have seen the problem occurring on several real world sites. One of them is: https://www.pressurecookrecipes.com/instant-pot-mushroom-risotto/#recipe where if you scroll up to the top from the recipe it'll jump back down to the recipe.
From the test case linked above: Click on "Go to element #foo" to scroll the page down to the #foo element. Then manually scroll back up here and click on the "Will it jump?" button to see the page scroll back to the #foo element. That scrolling is the issue - the page should NOT scroll. The button here is simply modify a <style> element. There are three seemingly unrelated preconditions that, when present on a page together, trigger this behavior:
PRECONDITION 1: Anchors The first is the presence of an anchor or "fragment identifier" in the URL. The fragment identifier must reference, by id, one of the elements on the page.
PRECONDITION 2: Dynamically Inserted Link Tag The second piece of the puzzle is that we need to dynamically add a element to the DOM. In order to trigger this issue, appending of the element must happen either via the "DOMContentLoaded" event or in the "readystatechange" event when document.readyState === 'interactive'. If the is added when document.readyState === 'complete', there will be NO jump. The contents of the file referenced by the href attribute don't matter. As seen in the demo here, the file could even be a 404 and the issue will manifest. Only if the "href" attribute is omitted will the issue not occur. <script type='text/javascript'> // document.addEventListener('DOMContentLoaded', () => { document.addEventListener('readystatechange', () => { if (document.readyState !== 'interactive') { return; } const link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.media = 'all'; link.property = 'stylesheet'; link.href = 'not-even-a-file.css'; document.body.appendChild(link); }); </script>
PRECONDITION 3: Dynamically Updating <Style> Tag For the final part, we simply construct a <style> element with document.createElement('style'); and add some CSS to it as a child "textNode". The actual CSS properties we specify don't seem to matter. I tested with font-size, color, and width but for this demo I leave any style properties empty. The CSS selector also does not need to match any element that is actually in the DOM! Each time the <style> element is updated, the page will jump to the element whose id is in the fragment. <script type='text/javascript'> const head = document.head || document.getElementsByTagName("head")[0]; const styleElement = document.createElement('style'); styleElement.type = "text/css"; head.appendChild(styleElement); const jumpBtn = document.querySelector('#jump'); jumpBtn.addEventListener('click', () => { const css = '#matches-nothing-in-dom {}'; const cssNode = document.createTextNode(css); const childNodes = styleElement.childNodes; const child = childNodes[0]; if (child) { styleElement.replaceChild(cssNode, child); } else { styleElement.appendChild(cssNode); } }); </script>
https://bugs.webkit.org/show_bug.cgi?id=244895
Browser Configuration
From webcompat.com with ❤️