2025/12/22 / Technical Note

Add Syntax Highlighting to Code Blocks in the Blog's CSS

A clear guide on how to implement syntax highlighting for code blocks in a blog using CSS and client-side highlighting libraries.

css

Hello! This is Pan.

In this post I summarize what I did to add syntax highlighting to code blocks on my blog.

The build process only formats and outputs the structure of code blocks; the visual styling is handled on the client side via CSS and a highlighting library. Below I describe the actual implementation I confirmed and the CSS and setup steps I added or adjusted, with concrete examples.

Build overview

The custom renderer in the build script outputs Markdown code blocks as the following HTML structure:

  • <figure class="code-block" data-lang="xx">: wraps the entire code block
  • div.code-header: displays a language label at the top
  • The intended build output shape is <pre><code class="language-xx">...</code></pre>

That's it.

For chart outputs using Mermaid, emit something like:

  • <div class="mermaid-wrapper"><div class="mermaid">...</div></div>

and let the client initialize Mermaid to render it.

In short, the build side's responsibility is to attach "which language" and "visual hooks" — actual coloring is delegated to a client-side library.

This design has the following benefits:

  • Lighter site builds (no tokenization or server-side highlighting)
  • Easier client-side theme switching
  • Easier handling of blocks that require client rendering (like Mermaid)

Steps I actually took (overview)

  1. Create CSS that matches the HTML structure emitted (.code-block family of rules).
  2. Add Prism.js (or highlight.js) to highlight <code class="language-..."> elements.
  3. If there are Mermaid blocks, call mermaid.initialize() on the client to render them.
  4. Implement line numbers, line highlighting, and dark-mode support in CSS (and add JS helpers if needed).

Below I include the sample CSS and Prism setup examples I used in the article. Adjust them to fit your project's conventions.

Sample CSS

An example I actually used. Change colors and fonts as you like.

/* Blog: base styles for code blocks */
figure.code-block {
  margin: 1.2em 0;
  border-radius: 8px;
  overflow: hidden;
  background: #0b0f14; /* example dark background. Override for light theme via another class */
  color: #e6eef6;
  box-shadow: 0 1px 0 rgba(0,0,0,0.15);
  font-size: 0.9rem;
}

figure.code-block .code-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: linear-gradient(90deg, rgba(255,255,255,0.03), rgba(255,255,255,0.01));
  border-bottom: 1px solid rgba(255,255,255,0.04);
}

figure.code-block .lang-icon { display: inline-flex; align-items: center; }
figure.code-block .lang-label { font-weight: 600; font-size: 0.85rem; color: #cfe3ff; }

figure.code-block pre {
  margin: 0;
  padding: 12px;
  overflow: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, "Roboto Mono", "Courier New", monospace;
  line-height: 1.6;
  background: transparent;
  color: inherit;
}

/* Prepare for line numbers or line highlighting (can be used with Prism plugins) */
pre[data-line] {
  position: relative;
}

/* Prism token colors are intended to be overridden per theme */
.token.comment { color: #6a737d; }
.token.keyword { color: #ff7b72; font-weight: 600; }
.token.function { color: #79b8ff; }

Loading Prism.js via CDN (example)

For quick testing you can load from a CDN. For production, prefer bundling or hosting locally.

<!-- Prism CSS and JS (example: CDN) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@latest/themes/prism-tomorrow.css" />
<script src="https://cdn.jsdelivr.net/npm/prismjs@latest/prism.min.js"></script>
<!-- Load language components you need -->
<script src="https://cdn.jsdelivr.net/npm/prismjs@latest/components/prism-javascript.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs@latest/components/prism-python.min.js"></script>

<!-- Prism plugins (line numbers, etc.) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@latest/plugins/line-numbers/prism-line-numbers.css" />
<script src="https://cdn.jsdelivr.net/npm/prismjs@latest/plugins/line-numbers/prism-line-numbers.min.js"></script>

<!-- Initialization is usually not required (Prism often runs on DOMContentLoaded automatically) -->

Note: tools/build-blog.js emits <code class="language-xxx">, so loading the corresponding Prism language components should color them automatically.

Handling Mermaid

Because the build emits a dedicated wrapper for Mermaid blocks, initialize Mermaid on the client.

<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
  mermaid.initialize({ startOnLoad: false, theme: 'base' });
  // build-blog.js outputs .mermaid elements, so after DOM is ready initialize each
  document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('.mermaid').forEach((el) => {
      try {
        mermaid.parse(el.textContent);
        // Simple render call
        mermaid.init(undefined, el);
      } catch (e) {
        console.warn('mermaid parse failed', e);
      }
    });
  });
</script>

Extra improvements worth adding

  • Line numbers
  • Line highlighting
  • Copy button
  • Light / dark theme switching
  • Server-side prerendering: since highlighting is client-side in this approach, consider running Prism during build to produce highlighted HTML if you want better first-paint performance or SEO.

Summary

  • Emit well-structured code blocks (labels, classes, data-lang) from the build, and let CSS + a client-side highlighting library handle coloring and fine visual adjustments. This makes implementation straightforward and easier to maintain.
  • For small blogs, using Prism and Mermaid from a CDN is a fast way to get things working; after testing, bundle them into your production build.
  • You can easily add user-friendly features like line numbers, copy buttons, and theme switching.

Thanks for reading! If you want, I can add a concrete CSS file to the project or explain how to integrate Prism into your build pipeline. Let me know which you'd prefer.

← C#14:New Feat…← Back to Blog