Reducing Initialization Flicker in tinyMCE

At Ubernote we have been using the tinyMCE editor for a long time. I've been happy to submit a few patches back to them, and this looks like another one that is going to go their way.

To change the default styling of the contents of your editor, tinyMCE has the ability to attach user defined stylesheets to the editor's <iframe> using the "content_css" option, and this takes care of most everything I need it to. Unfortunately, the loading of the CSS happens after a noticeable delay once the contents of the editor area already loaded. In our editor's CSS, we reset the margins and paddings to 0, as well as reduce the default font size to .8em. Most browsers have a default body padding of 10px, with a default font-size of 1em. Because of this, when tinyMCE first loads up, the contents within the editor's body are slightly indented and the contents of the editor are 1em. Once the stylesheet is downloaded and processed, the padding goes away, and the font size is reduced. This process, even on fast machines, is noticeable. On slow machines it is a second more more. Not exactly pretty behavior.

Normally when loading a web page, CSS files are attached in the <head> of the document. The CSS is downloaded and processed before the rest of the contents are displayed, and your document appears how you want it to. Unfortunately, tinyMCE has had to work around a lot of browser incompatibilities, because of this the author had to load up the contents of the editor's <iframe> and then after a slight delay attach the CSS, which is where this flicker comes from.

The question I asked myself in a complete "duh" moment was, "So why not attach a styling directly to the body before the CSS is loaded?" Elegant? From a purist standpoint, no, not really. Does it work? Yes. At least we can make things slightly more generic and make the styling we want to attach a configuration option.

This solution does require modification of the tinyMCE code, so make a backup of your tinyMCE directory before you start editing.

In the classes subdirectory, find Editor.js. Load it up.

In init, find the following line:

    t.iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>';
Replace it with:
    var bs = s.body_style || '';
    if (bs.indexOf('=') != -1) {
        bs = t.getParam('body_style', '', 'hash');
        bs = bs[t.id] || '';
    }

    t.iframeHTML += '</head><body style="' + bs + '" id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>';

What we did here is simple. We are looking in the settings for an option called 'body_style'. Process it like the 'body_id' and 'body_class' before it. This extra processing is in case the parameter was given as a hash for multiple editors, find the body_style for this particular editor instance. Then, when we create the body for the IFRAME, we are setting the style to be the style we passed in in our body_style parameter.

To use this in your tinyMCE.init, you would add a line in your configuration such as:

    // previous configuration items
    body_style: 'padding: 0; margin:0; font-size: .8em;'

Notice the lack of flicker.