How to Create Responsive Code Blocks

How often have you started reading a technical article on your phone, yet given up halfway through because you got tired of scrolling sideways through code blocks? If you have your own blog, are you giving this same annoyance to your readers?

In this post I’m going to look at how to adapt code blocks for mobile devices on your blog, and why it’s worth the effort.

TL;DR

At a technical level it’s easy to do - so long as you have the flexibility of having your own site, that is. The hard work is simply taking the time to format your code in two different ways by hand. Given how important it is to support mobile devices, we can’t let our code samples in our articles fall behind here.

Why Bother?

One of the advantages (and challenges) of creating your own blog is that you get to create a blog that you’d enjoy reading yourself - e.g. no annoying cookie popups and no ads. If you try reading your articles with code samples on mobile, you might find like I did that your code samples are hard to read.

So first off, you simply avoid passing on this same annoyance to your readers.

Take advantage of the flexibility of your own blog

Here you can have an advantage over blog platforms like dev.to which give you simple editors for your posts, and therefore force you to choose between code that reads well on large screens or reads well on small screens, but not both.

Us indie bloggers don’t have a huge number of advantages over large platforms, so it’s worth making full use of any such edge where you can.

Most readers are on mobile

I was rather surprised to find that, according to my site analytics, about two-thirds of the readers on my blog are on mobile! Even for a code-sample-heavy post like my elisp cheat sheet, which I expected would be used more often when people are currently coding and therefore on a large screen, had a large number of small-screen readers.

If so many readers are on mobile, it’s worth making sure they get to have as good an experience as those on a large screen. It’s all too easy to forget this as a writer as you’re usually on a large screen when writing

You need to optimize for both formats

Writing a technical article, especially one that offers code samples, will likely have a different usage pattern than most other web articles; your readers may very likely come across your work on mobile while viewing their news feeds, then perhaps come back to it again later to refer to while coding.

Therefore you need your code samples to be readable on all screen types; not falling off the page on mobile, nor being formatted in an unnatural manner on widescreen.

How to implement it

Sadly, you can’t make code blocks automatically responsive like normal text is - so unfortunately you need to create two different versions of your code samples, by hand; one for small screens and another for large. You then need to switch between the two using a combination of CSS Media queries and the HTML ‘hidden’ attribute.

Different versions of the code

As recommended in this post, ideally for narrow screens you want to

  • limit line lengths to around 32 chars
  • use only 2 spaces for indentation

For example, if you had the code

function compactObject(val) {
    const data = Array.isArray(val) ? val.filter(Boolean) : val;
    return Object.keys(data).reduce(
        (acc, key) => {
            const value = data[key];
            if (Boolean(value))
                acc[key] = typeof value === 'object' ? compactObject(value) : value;
            return acc;
    },
    Array.isArray(val) ? [] : {}
  );
};

your mobile-optimized version would look like

function compactObject {
  const data = Array.isArray(val)
    ? val.filter(Boolean)
    : val;
  return Object.keys(data).reduce(
    (acc, key) => {
      const value = data[key];
      if (Boolean(value))
        acc[key] =
          typeof value === 'object'
          ? compactObject(value)
          : value;
      return acc;
    },
    Array.isArray(val) ? [] : {}
  );
};

The former is perfectly reasonable on widescreen, but a bit awkward to read on mobile due to the horizontal scrolling required. But with some carefully chosen line breaks it’s more practical for narrow screens.

CSS Media Queries

Simply put, CSS media queries let you modify the behavior of your CSS depending on aspects of the currently active viewing media, which 99% of the time is a check on viewport width.

In your HTML you just need to identify your two code block versions with their own classes, e.g.

<code class="narrow">
// narrow code version
</code>

<code class="wide" hidden="true">
// wide code version
</code>

then you include the following media query in your CSS:

@media (min-width: 640px) {
    .narrow {
        display: none;
    }

    .wide {
        display: block;
    }
}

With this in place, the browser will switch between the two code versions depending on screen size.

(I’ve chosen 640px as the breakpoint here, but you can adjust this to your preference.)

HTML ‘hidden’ attribute

You might be tempted to take a pure-CSS approach here to avoid using the hidden="true" attribute in the wide code version. However, it’s important you use that attribute to ensure proper display for reader modes. Such readers don’t use CSS at all, in which case both code block versions would be displayed! Therefore by using the attribute, you ensure that you only display one of them in CSS-less environments.

I’ve placed the attribute on the wide version to make use of the narrow version in reader modes; this is because reader modes tend to have narrow widths and large font sizes for code blocks, and so the narrow version is generally easier to read in reader modes, even on desktop.

Implementing in Hugo

I use Hugo as my static site generator. To make use of the above within a markdown content file as used by Hugo, you have a couple of options:

  1. Enable unsafe HTML in Hugo’s markdown template settings, and simply write the HTML markup as described above
  2. Use shortcode templates

I’ll run through how to use option 2, which is what I’ve chosen to do myself; this is because I prefer to keep the ‘unsafe HTML’ option off, and also it’s slightly shorter to write within my markdown content files.

You simply need to create a couple of shortcode templates, one for each code block format.

Firstly, you have layouts/shortcodes/narrow.html:

<div class="narrow">
{{ .Inner | markdownify }}
</div>

and secondly, layouts/shortcodes/wide.html:

<div hidden="true" class="wide">
{{ .Inner | markdownify }}
</div>

Note that I’ve used div elements rather than code elements in the markup since the code elements will be generated by Hugo when it renders the markdown. Otherwise, everything works much the same in principle as the raw HTML version described above.

With the shortcodes created, you can use them in a Hugo markdown content file like so:

{{< narrow >}}
```
// Narrow code
```
{{< /narrow >}}
{{< wide >}}
```
// Wide code
```
{{< /wide >}}

Acknowledgements

Thanks to: