New Solution is currently with a new approach to implement scrollable iframes. It’s described in detail in . AMP experimenting AMP, iOS, Scrolling Redo 2 — the shadow wrapper approach The problem and the original solution This article is a follow up on the problem and solution described in the original post . AMP, iOS, Scrolling and Position Fixed To reminisce, AMP documents are often shown in a iframe. The structure would normally look like this: scrollable <html><head><title>I'm a Web App and I show AMP documents</title><style>iframe {position: absolute;top: 0;left: 0;right: 0;bottom: 0;}</style></head><body><iframe … width="100%" height="100%" src=" "></iframe></body></html> scrolling="yes" https://cdn.ampproject.org/c/pub1.com/doc1 This generally works great in most of browsers. We did try many other approaches, including sizing iframe by the content and scrolling the main document. But they all have significant functional detriments and performance issues. See the for details. original post However, iOS Safari does not support scrollable iframes. In other words is simply ignored. See . The long-standing iOS Safari issue can be found at . scrolling="yes" this demo bugs.webkit.org/149264 We found an original workaround codified in the . In short, we scroll the actual element of the document. Thus, even though the iframe itself does not scroll, the content of the iframe does. ViewportBindingNaturalIosEmbed_ <body> The resulting AMP document looks like this: <html AMP ><head></head><body ><!-- document content --></body></html> style="overflow-y: auto; -webkit-overflow-scrolling: touch;" style="overflow-y: auto;-webkit-overflow-scrolling: touch;position: absolute;top: 0;left: 0;right: 0;bottom: 0;" The iframe now scrolls! This has been the solution we used in AMP for a year. However, a list of problems was adding up over time. The are described in detail in , but in short: original post Applying on the is unexpected and interferes with author styles. One side effect, for instance, is we don’t allow customizing margin on the element. position:absolute <body> <body> Body’s , , and do not work due to . This is solved by injecting DOM with “fake” measuring elements as described in the . scrollTop scrollLeft scrollHeight scrollWidth bugs.webkit.org/106133 original post is buggy inside the container. See . position:fixed -webkit-overflow-scrolling:touch bugs.webkit.org/154399 Offsetting headers and footers requires setting border on which is expensive, reduces scrollable area and occasionally breaks existing layouts. Hiding headers causes significant jumps in UI and broken scrolling. <body> Can we improve on this? Enter the new solution… The new solution — the wrapper approach The new solution is codified in the . ViewportBindingIosEmbedWrapper_ DOM structure At its core, the wrapper approach is similar to scrollable . Iframes still don’t scroll in iOS Safari and thus we need to scroll the content of the iframe. Since scrolling has a lot of problems, we could create a scrollable wrapper and place it between and elements. In other words, we would wrap the element in the scrollable container. <body> <body> <html> <body> <body> So, the new DOM structure would look like this: <html AMP ><head></head> > <!-- document content --></body></i-amp-html-wrapper></html> style="overflow-y: auto; -webkit-overflow-scrolling: touch;" <i-amp-html-wrapperstyle="display: block;overflow-y: auto;-webkit-overflow-scrolling: touch;position: absolute;top: 0;left: 0;right: 0;bottom: 0;" <body style="position: relative;"> While this inarguably looks very “strange”, it does indeed solve the original problem — it makes iframes scrollable on iOS Safari. In addition this also solves many problems described above: There are no special requirements forced on the element: it’s normally positioned and has the default style. AMP allows most of CSS styles anywhere in the DOM so this reduces our interference with authors’ styling. <body> overflow:visible The scrollable wrapper element can be used to read , , and and thus “fake” measuring elements described in the are no longer needed. scrollTop scrollLeft scrollHeight scrollWidth original post Offsetting headers and footers no longer requires setting a border on the — simple padding on the wrapper element is sufficient. <body> However, the problem is still present in this solution. More on this later. position:fixed Two <html> elements We implemented the wrapper solution and quickly ran into a small problem. A lot of people like to use selectors which we broke by injecting between and . As a fix, we renamed to . html > body i-amp-html-wrapper <html> <body> i-amp-html-wrapper <html> The final DOM structure now looks like this: <html AMPstyle="overflow-y: auto; -webkit-overflow-scrolling: touch;"><head></head> style="display: block;overflow-y: auto;-webkit-overflow-scrolling: touch;position: absolute;top: 0;left: 0;right: 0;bottom: 0;"><body style="position: relative;"><!-- document content --></body></html></html> <html id="i-amp-html-wrapper" Double the “strange”, double the fun. But CSS selectors now work correctly. html > body Implementation AMP runtime creates wrapper as early as possible in the startup. The existing element is simply reparented inside the wrapper: <body> // Create wrapper.const wrapper = document.createElement( );wrapper.id = ; 'html' 'i-amp-html-wrapper' // Setup classes and styles.wrapper.className = document.documentElement.className;document.documentElement.className = '';document.documentElement.style = '...';wrapper.style = '...'; // Attach wrapper straight inside the document root. document.documentElement.appendChild(wrapper); // Reparent the body.const body = document.body; wrapper.appendChild(body);Object.defineProperty(document, 'body', {get: () => body,}); This code is mostly straightforward, with a small nuance — reparenting the body resets to , thus we need to override property back to the original element, which is done using . document.body null document.body <body> Object.defineProperty Position:fixed problem While the wrapper approach solves many issues, the problem still remains. position:fixed This problem is described in detail in the . The related iOS Safari bug is . original post bugs.webkit.org/154399 In short, a element inside the container jumps and flickers when scrolling. It looks like the element is slightly scrolled and then quickly jumps back into its correct place. See this . position:fixed -webkit-overflow-scrolling:touch position:fixed video for demo In our original solution, we move qualifying elements out of the original and into the synthetic “fixed layer” element that’s placed in DOM outside the container. position:fixed <body> -webkit-overflow-scrolling:touch The final DOM structure looks like this: <html AMPstyle="overflow-y: auto; -webkit-overflow-scrolling: touch;"><head></head><html id="i-amp-html-wrapper"style="display: block;overflow-y: auto;-webkit-overflow-scrolling: touch;position: absolute;top: 0;left: 0;right: 0;bottom: 0;"><body style="position: relative;"><!-- document content --></body></html> ><!-- fixed elements reparented here --> </html> <body id="i-amp-fixed-layer"style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;pointer-events: none;" </body> Thus, we end up with two elements and two elements. It looks completely crazy, but it does solve the two original problems: iframes now scroll and elements do not flicker. <html> <body> position:fixed Obviously, we’d be much nicer if the underlying iOS Safari issue were fixed ( ). bugs.webkit.org/149264 References Original solution: AMP, iOS, Scrolling and Position Fixed Webkit bug: IFrame scrolling=yes is ignored in iOS Safari Webkit bug: document.body.scrollTop & document.documentElement.scrollTop differ cross-browser Webkit bug: Position fixed is buggy with overflow:auto scrolling is how hackers start their afternoons. We’re a part of the family. We are now and happy to opportunities. Hacker Noon @AMI accepting submissions discuss advertising &sponsorship To learn more, , , or simply, read our about page like/message us on Facebook tweet/DM @HackerNoon. If you enjoyed this story, we recommend reading our and . Until next time, don’t take the realities of the world for granted! latest tech stories trending tech stories