It sometimes amazes me that after being in web development for as long as I have, some things can still jump up and bite you if you haven’t run into them before. This past week I ran into one such occasion.

I was developing a web-based “FTP” application for one of my clients, with Job 1 being “it has to work on the Mac”. The previous application that had been developed for this client by a third-party was clunky to use, both from a front-end and management area perspective, oftentimes would not work quite right, and many times outright fail – and 95% of the system errors occurred on Macs due to the way the code was written. Cutting out a lot of the details, the new system proposed would work like so… a front-end user would log into the system, be able to manage their previously uploaded files or view files that my customer had sent to them via the application, or upload a new file. If they uploaded a file, the page they looked at contained a few form fields which would be inserted into the database, which mostly helped track which Job Number the file belonged to and some other relevant data, a comments field, and the file field itself. The page also included two iframes, one hidden and one visible; we had decided to go with a simple remote scripting solution because we felt in the interest of the client’s budget that we wouldn’t try and implement anything fancier. In order to keep the user looking at the page they were currently on, the form had the target attribute point to the hidden iframe where it could process the information but otherwise keep the user in “stasis”: the second iframe would load a fairly standard progress bar upon form submission which would reload itself to allow user feedback for the user uploading the file, letting them see how their upload was doing as they waited. Once the actual processing script was complete, with the file written to the server’s hard drive and the database inserts all doing what they needed to do, an alert would be raised to the user letting them know the upload was successful and they would be redirected back to their main view.

All well and dandy, and this didn’t take too long to implement either. The management forms and reports along with dealer/user management functionality took longer than getting the critical functionality to work. Once it was all done, it was sent off to my client in a staging location where they could kick the tires a bit and see what they thought after I gave them the on-the-phone walkthrough of what their users would be going through, and how to use all their new tools for their side of the application as well.

Things went great and the client was extremely pleased… but one minor bug came up during our walkthrough. Apparently when my client clicked to upload her file, a popup window came up to execute the form processing script. What? The application had been tested in Windows IE6, IE7, Firefox2, Opera9, and Mac Firefox2 and Safari3 – we had figured we covered our bases pretty well, even if wasn’t EXHAUSTIVE testing for everything out there. She reported she was running Safari 2.0.4, and so began my joys of tracking down why exactly this may be happening. Google was surprisingly unhelpful, as many of the people asking for help with similar issues in online forums were being greeted with “have you tried this?” responses which were all pretty boilerplate stuff – nothing that really explained the issue nor any real definitive answers. Then I started finding some interesting suggestions after a lot more digging. Move the iframe above the form (or link) referencing it via the target attribute; apparently some browsers will not recognize the target if it did not exist in the DOM before it was referenced. Ensure your iframes have both id AND name attributes (mine already did). Don’t use display:none on your iframes… wait, what?

I believe the issue here comes from some confused implementation of the Permissive Policy that Safari 2.0.4 has in place – especially since the linked document says that Safari 3 also institutes the Permissive Policy, yet that version of the browser works just fine. Long story short, if an iframe has display:none set on it, Safari refuses to acknowledge the iframe as part of the DOM. As such, if you attempt to target a “hidden” iframe, Safari 2.0.4 will create a popup window the same way any browser will create a popup window if you set the target of an anchor to a name it does not recognize – it simply believes you are trying to create a named child window. How we get around this problem is as simple as it is stupid. Don’t try and hide the iframe, but give it width/height values in its style and ensure you have the border set to zero as well (side note: in my experience I have still found it always best to not only set the border in the style but also continue to use the frameborder attribute since some browsers don’t properly recognize the border style on an iframe; which means setting a border of “0px” may still leave you with a border). Once I had my iframe styled with a 1px-by-1px size with no border, I called my client to once again give it a shot. Lo and behold, the problem went away and the page functioned the way it was intended.

I understand some of the security in place per standards that have been set either by the W3C or other groups/organizations that exist to look out for the greater good, but especially when a simple workaround like this exists I still can’t tell if this is a bug or an intentional “feature” that just happens to be easily circumvented. With Safari in version 3 I don’t imagine Apple will be releasing an update for this issue anyway, even if it is a true bug, but it’s still something that I have shared with multiple other developers I know and not a single one can believe what I have told them. I guess you do learn something new every day.

2 Responses to “Safari 2.0.4 and iframes”

  1. #1 The Booty Hunta says:

    Thanks. That works!

    I had been searching around for hours looking for a solution, before I found your site.

  2. #2 Using SWFUpload with Django » I Am Cloudtunes says:

    [...] a traditional HTML form that submitted to an invisible iframe (Safari users watch out: the iframe cannot be hidden), it just wasn’t as smooth as it needed to [...]

Leave a Reply