Developing a web page is easier when your changes are instantly reflected in the browser. One of the fundamental features of CodePen is the live update you get while developing in the CodePen editor. It makes writing HTML and CSS faster because you get instant feedback.

CodePen saves the HTML, CSS and JavaScript of a Pen as a new web page every single time you make a change. It then serves a new iframe with a unique URL to that web page. Serving the iframe Pen preview as a page reload is the most reliable and bug free solution we've found.

This is more reliable but it's also a bit heavy on the browser because it continually reloads a full webpage on every edit. If a change to a Pen is only CSS we could be smarter and dynamically update only the CSS. That's what we did.

Updating only the CSS makes the page rerendering feel faster, maintains the state of the web page (text inputs don't change, scroll position stays the same) and CodePen handles one fewer web request.

Here's how we did it and the mistakes we made.

V1

The first version of our style update was simple. It grabbed the single style element by ID and updated the innerHTML value.

This worked for me on Safari, FF, Chrome, Opera and IE11. Unfortunately we got some complaints that the CSS updates no longer worked.

V2

I'd already read how LiveReload dynamically updates it's CSS but I'd considered it overly complicated when I thought that updating the innerHTML worked. After the bug reports I decided to give their solution a try.

This solution is much more reliable. It basically looks for any style element with the class name cp-pen-styles. The meat and sweet potatoes is below.

  • Step 1 - find previous style element.
  • Step 2 - clone it
  • Step 3 - update inner CSS of cloned node in cross browser way
  • Step 4 - append newly cloned not to head
  • Step 5 - remove old style element
  function refreshCSS(css) {
  var prevStyle = findPrevCPStyle();
  var newStyle  = document.createElement("style");
  newStyle.type = "text/css";
  newStyle.className = "cp-pen-styles";

  if (newStyle.styleSheet){
    newStyle.styleSheet.cssText = css;
  } else {
    newStyle.appendChild(document.createTextNode(css));
  }

  getHeadEl().appendChild(newStyle);

  if (prevStyle) {
    prevStyle.parentNode.removeChild(prevStyle);
  }
}

Since we don't have access to jQuery or any other library we use simple JavaScript. Unfortunately we found 1 more problem.

Keyframes.

Keyframes never update after a dynamic CSS update. If we detect keyframes exist we update the entire web page.

Problem Solved

This solution has worked well for over 2 weeks and thousands of users. In the future it may be possible to dynamically update the JavaScript, but that's a whole nother bag of peanuts.


4,434 3 17