Sunday, September 21, 2014

iFrame & iOS 7 Safari (Issues, workarounds & limitations)

As a developer, I must admit that iFrame does make developer's life easy but they are not browsers' best friends. We are using iFrame in one of the ebook reader products we are creating and really struggled to get it working on iOS 7. There are multiple ways to work with iFrame on iOS 7:
  1. Setting the iScroll's scrollable property to "yes" doesn't make the iFrame scrollable but actually increases the height of the iFrame to match it's content. So, if you specified the height of iFrame to be "600px" but the content is 12000 px, the iFrame's height actually becomes 12000px which means the parent document's body scrolls and not the iFrame itself, which may defeat the purpose of using an iFrame.

  2. Another approach that I discovered by reading blogs was to wrap the iFrame inside a container div with a fixed height and set the iFrame's height to match it's content and set it up as follows:

    <div style="overflow:scroll; position:absolute; -webkit-overflow-scrolling: touch; width:100%; height:100%;">
        <iframe scrolling="no" style="width:1000px; height:6000px;" src="my_page_url.html"></iframe>
    </div>
    As you can notice, the container div has a fixed height where as the iFrame is larger to match its content. The most important thing here is the style applied on the parent div i.e. "style="overflow:scroll; -webkit-overflow-scrolling: touch;". This is what informs the webkit browser that the div is supposed to scroll and should scroll on touch. Unless you specify this style on the container div, the div will NOT scroll on iOS. You can follow the same approach on all WebKit compatible browsers. This approach will work and make the container div only scroll, however, this approach has it's caveats and we will talk about it later in the article.

  3. The third and final approach I discovered is only feasible when you've control over the document that is loading inside the iFrame. This involves modifying iFrame document's DOM which is possible only when loading documents from the same domain as the parent. In this approach we'd turn the iFrame's scrolling to "no" and also keep it to a fixed size so that the containing div or the parent body doesn't scroll. To achieve the scroll we'd need to inject a container div into the iFrame body and make it overflow. The div can be inject using a code snippet like this:

    iframeDocumentBody.innerHTML = "<div style="overflow:scroll; position:absolute; -webkit-overflow-scrolling: touch; width:100%; height:100%;"> + iframeDocumentBody.innerHTML + </div>

    This will ensure that you actually have a scrolling iFrame.

Now that we have seen 3 different approaches to get the iFrame to work, let us understand the caveats that each one of the above possesses:

  • Approach #1 has the biggest caveat that the iFrame itself doesn't scroll and the container document scrolls.
  • Both approach #1 and #2 present memory issues on iOS Safari. As the iFrame goes longer, the iOS Safari consumes more virtual memory to load the same. So, if you have a 20000 px long iFrame and it contains an HTML video or audio element, the page will CRASH on load. Not certain what happens here but it seems that iOS tries to create a huge place holder for the iFrame and crashes while allocating memory. The memory management works better in case of approach #3 and the page doesn't crash with the same content.
  • Although, following approach #3 solves the problem with crashing on load, however, with all 3 approaches, the iFrame with huge overflow and a media element (audio / video) will crash when you scroll at a very high speed. So audio or video inside the iFrame are not liked by Safari and should be avoided. Best if they can be added to the main document instead.
  • Text Selection: The selection of text works fine with all the three approaches, but with approach #2 and #3 when you scroll the page, the selection doesn't move along with the scroll. This is a bug with iOS safari, which means that it is unable to move selection with any overflowing element doesn't move with the scroll. Sadly, I haven't found any workaround for the same yet. If anyone knows about any work around, please let me know too :D

  • So, as I covered above, there are several issues with the iFrame on iOS 7. I have not got my hands dirty on iOS 8 so can't say what will change. Till that time, I would recommend NOT using iFrame till it is absolutely important. If you still do, I hope the tricks above will help you. If you have anything to add or want to suggest a better approach, please comment and I will modify the post.

No comments:

Post a Comment