Carbon: Basic Syntax Highlighting with Zero Overhead Using JavaScript

on in JavaScript DOM
Last modified on

Carbon: Basic Syntax Highlighting
Carbon: Basic Syntax Highlighting

If you have ever used PrismJS or CodeMirror or any other syntax highlighter solution, you’ll know it adds lots of dependencies bases on what language support you need. If you need HTML, JS and PHP support, you’ll add at least 2 JavaScript files and 2 CSS files. If you have lots of articles with code areas, it quickly adds up and impacts your page loading experience.

I have come up with a simple solution for styling a <pre> preformatted tag and adding line numbers. It’s enough for what I need, and it’s 273 bytes gzipped (424 bytes uncompressed).

Note that the code content is selectable and the line numbers are not, which makes it easy to copy the code. Also, it supports multiple preformatted areas on the same page.

Here’s the basic JavaScript code:

(function() {
    const pre = document.querySelectorAll('pre'),
          pl = pre.length;

    for (let i = 0; i < pl; i++) {
        pre[i].innerHTML = `<span class="line-number"></span>${pre[i].innerHTML}`;
        let num = pre[i].innerHTML.split(/\n/).length;
        for (let j = 0; j < num; j++) {
            let line_num = pre[i].getElementsByTagName('span')[0];
            line_num.innerHTML += `<span>${(j + 1)}</span>`;
        }
    }
})();

The JavaScript code above splits the <pre> content line by line and adds a line number in front of it. I am using a Flex CSS layout to make everything flexible.

Here are the CSS styles:

pre.carbon {
    display: flex;
    background-color: #eee;
    overflow: auto;
    margin: 0 0 1em;
    padding: .5em 1em;
}

pre.carbon code,
pre.carbon .line-number {
    font: normal normal 14px/16px "Cascadia Code", "Courier New", Courier, Monospace;
    color: #000000;
    display: block;
}

pre.carbon .line-number {
    margin: 0 1em 0 -1em;
    border-right: 1px solid #666666;
    text-align: right;
    user-select: none;
}

pre.carbon .line-number span {
    display: block;
    padding: 0 .5em 0 1em;
}

And here’s an HTML sample in a Carbon preformatted area:

<div class="example">
    <span>Lorem ipsum dolor sit amet...</span>
</div>
(function() {
    let s = document.createElement('script');

    s.src = 'carbon.min.js';
    s.id = 'carbon';
    s.type = 'text/javascript';
    s.async = true;

    document.body.appendChild(s);
})();

Pretty awesome, right?

Related posts