Your embedded Marketo forms are about to break in Firefox. Here's a fix.

Marketo user ED and I independently discovered (see this post) that once Firefox DE upgraded to v46, embedded forms would no longer submit.

It only took me a short time to find the cause and develop a fix (though that first iteration required a patched version of forms2.js, which you don't need anymore).

Much as I like drawing things out, I'll save the gory details for a moment and give you the fix:

    #MktoForms2XDIframe {  
        visibility: hidden;  
        position: absolute;  
        display: block !important;  

Insert that CSS rule either in your page or in an external stylesheet. Either way, make sure to place the rule/link before you load forms2.js (or forms2.min.js if you're loading the minimized version, which you might as well BTW).

You'll want to add the rule to any page that uses Forms 2.0 embed code(s). Most people only use the embed code on an external pages and not on Marketo-hosted LPs, since Marketo LPs have native forms support (the drag-and-drop Form object in a free-form LP, for example). But it is possible to use the embed code on a Marketo LP — me being me, I've done that a few times when testing advanced tricks — and if you do use the embed code in this context and make it cross domains, it too will break. But otherwise you don't have to worry about Marketo LPs.

With the fix out of the way and you hopefully breathing easier, here's some more detail about what broke and why.

First, understand that Firefox Developer Edition is a "technology preview" edition of Firefox that represents the browser as it will appear (give or take bug fixes) a month or two later. Check the release calendar for examples. The intent is that DE will be used by web developers who want to build for new technologies before they go live to the rest of the world. You can't roll out code to the public that requires DE-only features until that version of DE has moved through Beta (within a few weeks) and into Release (a few more weeks). But once version N becomes the Release, assume that everyone around the world will start using it that day (in reality, it'll be the next time they restart after an upgrade, but plan as if everyone restarts immediately).

So when Marketo says they "don't support Firefox DE" that isn't really the wrong position to take today, because supporting a browser version that isn't yet released can be difficult, especially if you have to build in forward and backward compatibility. The better answer, though, is "we will support it by the day of release," which I would not expect to happen without properly scary posts like this one and the companion Community post.

OK. So what broke? Firefox 46 (more accurately, Gecko 46) changed the way the venerable method Window.getComputedStyle works when called from inside a non-displayed IFRAME or OBJECT. (Let's hold off on why there's such an IFRAME in the mix and talk about the direct cause.)

What's fascinating about cases like this is that often the feature vs. bug debate ("Browser X is doing it right, Browsers Y and Z are wrong") has been going on for years with no firm resolution. So you can see people discussing Firefox's choices from 2010 onward. Meanwhile, code supporting both interpretations moves in and out of the Release codebase, often by accident because there's no resolution. When you see bugs that are left Open for 6 years, you smell trouble. If the standards aren't emended to confront this exact case, the "right" answer is a moving target, at least for that browser. (Luckily the other major browsers don't seem to be debating this one.)

The direct cause, then, is that forms2.js expects getComputedStyle to always return a CSSStyleDeclaration object, even if the object is empty. But, in Gecko 46, getComputedStyle may return null in certain contexts. If code doesn't cover that case, it will break with a fatal error. When forms2.js tries to use getComputedStyle from inside an IFRAME with display:none (which is one of those "certain contexts"), it errors out. Thus the IFRAME, which is critical for cross-domain embedded form posts to work, is never actually operational. The form will render and even validate accurately (those parts are not dependent on the IFRAME) but will not submit.

The fix, as you may have already figured out, is to set the IFRAME as visibility:hidden rather than display:none, in which case it is no longer "non-displayed" and can use all the expected methods.

I should probably save the question of why Forms 2.0 uses a non-displayed/hidden IFRAME for another post, but let me summarize it here. The interstitial IFRAME (which need not actually be hidden) is a classic, backward-compatible way to allow the cross-domain, bi-directional communication we need when POSTing a form across domains and processing the response. There's newer, more elegant (ok, that's debatable!) technology called CORS for this. But there's certainly nothing wrong with using this ol' thing, and no reason to expect it to stop working. (In fact, the IFRAME pattern still works just fine, it's more a coincidence that this particular method is broken and was used within the pattern.)

Comments and questions?