Destyling a Marketo form (for easier CSS restyling)
It's easier to customize a Marketo form if it's completely destyled to start. A float
or margin-left
that doesn't seem to respond to !important
can drive a designer crazy, and time spent on CSS specificity & cascade behavior isn't well spent.
My li'l snippet for removing Marketo's built-in styles has seen a lot of use via the Community and a few code versions (now at the venerable v1.104) but it hasn't appeared on the blog before.
Here's a sample form with the Simple theme:
And here's that same form after running destyleMktoForm
to reset it to browser defaults (check out the Times New Roman):
Yes, it's supposed to be ugly! All of Marketo's layout, visibility, and font CSS has been removed, and the world is your oyster from here. I'm not here to show you how to make it pretty (I get paid for that, sometimes!) but now you can assure your designer that they won't have to do any CSS overrides. They can look at the <form>
's HTML markup and style away.
About the code
Let's dive into the destyleMktoForm
function a bit, since I always insist on a teachable moment. The goals:
- hide the form to start: see
visibility: hidden
in the CodePen CSS pane[1] - remove all
style=
attributes within the form (these are really pesky to override) - disable local
<style>
sheets within the form - disable remote
<link rel="stylesheet">
includes within the document<head>
, if they were injected by the Forms 2.0 library - show the form with
visibility: visible
- re-run the destyling code whenever the form is re-rendered, i.e. via Visibility Rules, by calling the function from
MktoForms2.whenRendered
instead ofwhenReady
(thanks, Mark!)
So we end up needing two simple loops, one for the style
attrs and one for the <link>
& <style>
els.
Remove style attributes
var styledEls = arrayFrom(formEl.querySelectorAll("[style]")).concat(formEl);
styledEls.forEach(function(el) {
el.removeAttribute("style");
});
Here I'm selecting all the child elements of the <form>
element that have a style
attribute (regardless of the value and regardless of the type of element — who cares, we just want to destyle it!).
Then I add to the array the <form>
element itself (which also has a style
).
Then loop over the array and remove the attribute. Completely easy.
(arrayFrom
is just a naïve function to convert array-like NodeLists, as returned by querySelectorAll
, to true Arrays so you can run all the fun JS Array methods. Don't worry about it, just use it.)
Disable <link> and <style> stylesheets
var styleSheets = arrayFrom(document.styleSheets);
styleSheets.forEach(function(ss) {
if ( [mktoForms2BaseStyle,mktoForms2ThemeStyle].indexOf(ss.ownerNode) != -1 ||
formEl.contains(ss.ownerNode) ) {
ss.disabled = true;
}
});
Get an array of stylesheets. forEach
over the array and if either of the following is true…
- the stylesheet has one of Marketo's known stylesheet IDs (base style and, in this case, Simple theme style)[2]
- the stylesheet is a child of the Marketo
<form>
element
… then set the stylesheet's disabled
attribute (a very cool, age-old feature) to true.
One other thing
One thing you may want to do (and which I do in my demo) is un-de-style the .mktoAsterix
element:
.mktoForm .mktoAsterix {
display: none;
}
.mktoForm .mktoRequiredField .mktoAsterix {
display: block;
}
See, Marketo includes the <div class="mktoAsterix">*</div>
(denoting required fields) in the form markup even for fields that aren't required. Then display: none
hides fields that aren't required. So when you clear all the styles, you see a lot of asterisks to clean up.
Of course you're free to work with all the rules off. This is just a suggestion.
Notes
[1] Why not display: none
here? Because the forms library depends on the form being in the flow to determine its dimensions. Test and you'll see the diff.
[2] Not mentioning one HTML factoid I'm taking advantage of here for shorter code. Anyone notice it?