Friday, January 1, 2016

Show Your Work: Markup and styles for showing code

It's been quite some time since I've posted. Everyone is busy, and has different priorities, and sometimes that leads to an erratic posting schedule. As another year ends, I thought I end it with a short post about something I do quite often...writing code samples online. Why this topic? Because it's one of the things that all UI engineers should be dealing with - writing about code is one of the ways we share knowledge, teaching and learning at the same time - and it's one of the ways we creatively express ourselves.

As for the more technical stuff about the topic - I've gone back and forth about how best to do it - how to mark it up so that it's still semantic but at the same time make the design look a little traditional and make the code example itself easy to reference, by saying something like "in Example 1, line 3 you'll see the reference to parseMarkerData". Typically, that means banding (each line an alternating color - like the old-style printer paper) and line numbers. The problem with line numbers is that either you typically use an ordered list (which has its semantic advantages) or somehow put the line numbers in the markup (which is not semantic). I don't like the ordered list, mostly because a list item is not necessarily an item - it may be more or less than an item - and the ordered list is typically very difficult to style because of all the built-in browser styles.

I, therefore, have been going with a slightly different approach...I've started using a BLOCKQUOTE tag (because I'm typically quoting a block of code) and a SPAN tag to identify portions of the quoted code. This allows me to use a 'header' to describe the code block as well as wrap the quoted code in a DIV tag to enable scrolling for large blocks and maintain semantics by using a CSS counter to show the line numbers. My code sample ends up looking something like this...

<blockquote class="code"><p class="header">Example 1</p>
  <div class="viewport">
    <span class="line">&lt;script&gt;</span>
    <span class="line">var terra = new d3.geo.earth(document.getElementById('map')), trans;</span>
    <span class="line"></span>
    <span class="line">terra.parseMarkerData('airport-data');</span>
    <span class="line">trans = document.getElementById('btnTransform');</span>
    <span class="line">trans.onclick = function(e) {</span>
    <span class="line">    var style = 'Equirectangular';
    <span class="line">    if (terra.style() === style) {</span>
    <span class="line">      style = '';</span>
    <span class="line">    }</span>
    <span class="line">    terra.style(style);</span>
    <span class="line'>  };</span>
    <span class="line">&lt;/script&gt;</span>
  </div>
</blockquote>

...and my CSS, with its use of pseudo classes (like nth-of-type and before) and a counter looks like this...

blockquote.code { counter-reset:line; border:2px solid rgb(51, 153, 187); border-radius:20px; box-shadow:4px 4px 4px rgba(51, 153, 187, 0.7); font-family:monospace; font-size:0.8em; margin: 0.5em; padding:10px; }
blockquote.code > p.header { border-bottom:1px solid rgb(192, 219, 229); font-size:1.2em; font-weight:bold; margin:0 0 0.2em 0; }
blockquote.code > div.viewport { max-height:20em;   overflow-y:auto; }
blockquote.code > div.viewport > span:nth-of-type(odd) { background-color:#efefef; }
blockquote.code > div.viewport > .line { display:block; }
blockquote.code > div.viewport > .line:before { display:inline-block; margin:0 1em 0 0; text-align:right; width:2em; }
blockquote.code > div.viewport > .line:before { counter-increment:line; content:counter(line); }

That's all there is to it. This combination ends up giving me something useful that looks decent. Something that looks like this...
If you want to see how this works in a real-world example, head on over to my D3 earth plugin example page where you'll find several uses of the code sample style.

No comments:

Post a Comment