Access options:

New web site is in beta: websemantics.uk. A far better experience.

New version available: Displaying code in web pages

Dramatically updated and revamped.
This version is deprecated but kept for archive reference.

Displaying code in web pages

author: mike foskett incept: 25th June 2006

last modified: 18th March 2016

I started this project (25th June 2k6), to display HTML, CSS or JavaScript code blocks, with a list of requirements:

  1. Reduce time spent creating code examples
  2. be semantically meaningful (X)HTML
  3. a cross-browser, cross-platform solution
  4. not break the visual layout
  5. keep within a set width
  6. maintain white-space for clarity
  7. be easy to cut & paste
  8. all visual styling via CSS
  9. optionally stripe each line of code for readability
  10. unobtrusive JavaScript
  11. work independently of CSS and / or JavaScript.

I also made a HTML text parser which I personally find exceptionally useful.

Example

Here's an example from the style sheet:


/* Correctly stating the code and pre elements is the core principle.*/
/* Coded here as a single line to demonstrate long lines and how it scrolls. */
pre { font: 100% courier,monospace; border: 1px solid #ccc; overflow: auto; overflow-x: scroll; width: 90%; padding: 0 1em 1em 1em; margin: 1em auto 2em auto; background: #fff7f0; color: #000 }
code { font-size: 120% }

So what was wrong with the old methods?

I was tired of seeing web pages break from overflow incorrectly applied. (X)HTML and style sheets were being misused to make the code fit into pages. And since wrap="off" was deprecated even textarea didn't function well enough.

Most methods either break the design, don't readily cut and paste, or use quick-fix textboxes.

So what's different?

The technique demonstrated begins with a semantic cross-browser cross-platform method, then adds visual styling using CSS, and finally colouring via unobtrusive JavaScript.

As a demo, each of the code areas on this page use the method. I'll be retro fitting to the rest of the site as time becomes available (read "never").

The coding specifics

The (X)HTML

Keeping the (X)HTML semantic is the best method of ensuring cross-browser cross-platform compatibility. Don't get me wrong standards are not the "be all and end all" of web development, far from it, but they should always form the basic building block.

So the mark-up used:

pre
A block level element which pre-formats it's contents in a fixed width font, retaining white-space and line-breaks and that's with or without CSS
W3C: Preformatted text: The pre element
code
An inline element which perfectly describes the intended content.
W3C: Phrase elements: The code element

<pre><code class="codelist">
//    code to display which may be wider than the width of the content area
//    Note all &, > and < characters must be replaced with &amp;, &gt; and &lt;
</code></pre>

A similar effect could be achieved by additionally styling the code element, but then formatting is lost without CSS.

The codelist class is provided purely as a hook for the JavaScript. It is possible to achieve the result without the class but I like to allow for cases where line highlighting is not required.

The CSS

Except for line colouring, all that is needed is a little style:


pre  {
    font: 100% courier,monospace;
    border: 1px solid #ccc;
    overflow: auto;
    overflow-x: scroll;
    width: 90%;
    padding: 0 1em 1em 1em;
    margin: 1em auto 2em auto;
    background: #fff7f0;
    color: #000
 }
code { font-size: 120% }
.odd  { color: #600; background: #fff7f0 }
.even { color: #006; background: #fff7f0 }
.rem  { color: #060; background: #fff7f0 }

It is always best to assume nothing when styling. I always remove browser defaults when coding then rebuild. It helps ensure similar rendering across different browsing technologies. Consequently:

  1. font size and family are restated. A nice mono-spaced font, just like a real text editor bless.
  2. The border stated defines the area visually. It looks damn strange with scroll bars without one.
  3. The two overflow statements have the combined effect of only allowing horizontal scroll bars.
  4. Take care with when stating widths. Avoid 100%, IE doesn't like it especially when mixed with padding.
  5. Top padding is set to 0 to compensate for an extra line which is generated because the code starts with a new line in the (X)HTML.
  6. If you state a foreground colour it is advisable to re-state the background colour too.
  7. It may be necessary to add a font-size for code too as different browsers apply different sizing. Remember this may not be the only place it is used, for example there are code elements used throughout this content
  8. The classes; odd, even and rem; are used by the JavaScript to apply text colouring.

Printing

I recently noted that print styles were not behaving, so here's the update:


@media print{

  #content pre {
    overflow-x:visible; overflow-y:visible; overflow:visible;
    border:1px solid #ccc;
    padding:0.5em 1em;
    white-space:pre-wrap;       /* css-3 */
    white-space:-moz-pre-wrap;  /* Mozilla, since 1999 */
    white-space:-pre-wrap;      /* Opera 4-6 */
    white-space:-o-pre-wrap;    /* Opera 7 */
    word-wrap:break-word;       /* Internet Explorer 5.5+ */
  }

  code {font:medium/150% times,serif; color:#003}
  pre code {font:small/130% courier,monospace}
}

The JavaScript

JavaScript is not required for the above to work. It adds text highlighting to each line.

The onload addEvent function

These days I always include an on page load handler. Which allows multiple onload routines to be run concurrently. My function of choice is Simon Willisons' excellent add load event.


function addEvent(func){
if (!document.getElementById | !document.getElementsByTagName) return
var oldonload=window.onload
if (typeof window.onload != 'function') {window.onload=func}
else {window.onload=function() {oldonload(); func()}}
}

addEvent(stripeCode)

Upon page load the functions stripeCode() and selectCode() are called.

The stripeCode function

The function stripeCode() does the text highlighting. "So what" I hear you say, "there's a lot of stripe functions available" (an excellent one may be found at Splintered ). Unlike lists and tables code elements do not have child elements to attach colour to. Consequently the usual stripe methods do not work.

There are no elements inside the code element to hook onto to create different coloured lines. Consequently I decided to create a new code structure from the existing content.

This requires:

  1. find and effect each occurrence of codelist
  2. create a new code element and initialise variables
  3. find the end of line marker
  4. check each content character stopping at an end of line marker. Not so easy given different browsers use different variations.
  5. create a new span element add a line of content and apply a colour class
  6. add to the new code element and reset variables
  7. finally replace the old code element with the new one.

Firstly a standard technique for working through the DOM to access the relevant content.

Test for an end of line marker. Because of the (X)HTML layout the first character(s) are markers. I reverted to old school JavaScript as I couldn't get modern methods to work in a consistent manner. There must be a simpler and quicker method, any ideas?

Remember this is a rendered document; IE uses a carriage return (#13), Firefox uses a linefeed (#10) and Opera (most correctly) used both (#13,#10).


function stripeCode(){

// Locate and isolate pre followed by code with a class of codelist
var pres=document.getElementById('content').getElementsByTagName("pre")

for (var g=0;g<pres.length;g++){
var cn=pres[g].firstChild.className;
if (cn=="codelist"||cn=="css"||cn=="html"||cn=="javascript"||cn=="php"){

  // create a new code element
  var newCode=document.createElement('code');

  // reset variables;

  // even: for odd or even line
  var even=false;

  // line content container
  var spanContent="";

  // codeContent= all the code elements content
  var codeContent=pres[g].firstChild.firstChild.nodeValue;

  // first character(s) should be the carriage return and or a line feed
  var crLF=codeContent.charAt(0);
  if (codeContent.charCodeAt(1)==10) crLF+=codeContent.charAt(1);

If a line contains "//" then the whole line is coded as a comment. Note multi-line comments are not catered for.


  // now work through the content character at a time
  for (var f=0;f<codeContent.length;f++){

    // test for an "end of line"
    if (codeContent.substr(f,crLF.length)==crLF){

      // check for CR and LF step if required
      if (codeContent.charAt(f+1)==crLF[1]) f++;

      // create a new span as the lines container
      var newSpan=document.createElement('span');

      // apply a class
      newSpan.className=even?"odd":"even";

      // check to see if its a comment
      if (spanContent.match("//")){
        newSpan.className="rem";
        even= !even;
      }

      // if no content add a space
      if (spanContent==""){
        spanContent=" ";
        even= !even;
      }

Please remember that only about 18 lines of code can be seen at screen resolutions of 800x600px. Splitting the code into smaller segments is advisable.


      //add line content
      newSpan.appendChild(document.createTextNode(spanContent));

      // add new line to the new code element
      newCode.appendChild(newSpan);

      // add CR or LF if required
      if (crLF.length==1) newCode.appendChild(document.createTextNode(crLF));

      // flip odd / even boolean
      even= !even;

      // reset line container
      spanContent="";
    }

    // otherwise add character to line container
    else spanContent+=codeContent.charAt(f);
  }

  // finally replace old code element with the freshly created one
  pres[g].replaceChild(newCode,pres[g].firstChild);
}
}
}

A commented file of the JavaScript is available: stripe.code.js.

Also see:

Which may prove be useful.

Site search & complementary navigation:

Site search:

Online tools

Related tools and articles

New to site

Most popular

Online tools

Inspect report: