Veröffentlicht am
28.5.2026
Zeilennummern in Astro-Codeblöcken mit CSS anzeigen
In vielen Dokumentationen, Tutorials oder weiteren Beispielen über das Programmieren findet man sie: Schön formatierte Codeblöcke mit entsprechenden Zeilennummern und farblich passender Syntax-Markierung für die entsprechende Programmiersprache. Auch Astro.js bringt bereits eine Markdown-Verarbeitung mit, die Codeblöcke aus .md-Dateien automatisch in HTML umwandelt und auf Wunsch mit Syntax-Highlighting versieht. Allerdings gibt es darin keine Zeilennummern und gerade für Codebeispiele sind diese unheimlich hilfreich, um die Funktionen im weiteren Verlauf des Artikels richtig erklären zu können. Glücklicherweise kann man mit CSS dieses Problem ganz einfach lösen:
pre {
padding-left: 1rem;
max-width: 100%;
overflow-x: auto;
/* Variables for the line number design */
--line-number-width: 2rem;
--line-number-gap: 0.75rem;
--line-number-color: rgba(115, 138, 148, 0.4);
/* Longer code lines should not wrap,
but instead be horizontally scrollable */
& code {
display: block;
width: max-content;
min-width: 100%;
}
/* Initialize CSS counter and set the
counter variable's starting value to 0 */
&.has-line-numbers {
counter-reset: line;
padding-left: calc(
1rem + var(--line-number-width) + var(--line-number-gap)
);
/* Format code */
& code {
line-height: 1.25;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
font-size: 1rem;
}
/* Insert line number before the code line */
& .line {
position: relative;
&::before {
content: counter(line);
/* Increment counter variable by +1 */
counter-increment: line;
/* Position line number correctly */
position: absolute;
top: 0;
right: calc(100% + var(--line-number-gap));
width: var(--line-number-width);
height: 1em;
overflow: hidden;
color: var(--line-number-color);
text-align: right;
user-select: none;
}
}
}
}
Sobald das HTML-Tag pre die Klasse has-line-numbers hat, erscheinen am linken Rand des Codeblocks die entsprechenden Zeilennummern. Allerdings setzt dieser CSS-Block dafür voraus, dass jede einzelne Codezeile in dem Element <span class="line"> eingebettet ist. Das folgende Beispiel veranschaulicht dies:
<pre class="has-line-numbers">
<code>
<span class="line">console.log("Hallo Welt");</span>
</code>
</pre>
Diese Arbeit wird bei Astro.js von dem Markdown-Parser übernommen, der aus dem Markdown das entsprechende HTML generiert. Für das farbige Syntax-Highlighting selber ist Shiki zuständig, dessen Doku du hier finden kannst.
Shiki in Astro.js richtig konfigurieren
Damit Astro.js und Shiki die Klasse line zu den einzelnen <span> Elementen hinzufügen, muss in der astro.config.mjs eine entsprechende Funktion hinzugefügt werden. Shiki nennt diese Funktionen Transformer. In meinem Beispiel sieht sie so aus:
/**
* Shiki transformer for Astro 6+ that adds the 'has-line-numbers' CSS class
* to the <pre> element if 'showLineNumbers' is detected in the
* markdown metadata.
*/
function shikiTransformerLineNumbers() {
return {
name: "shiki-transformer-line-numbers",
pre(node) {
const meta = this.options.meta;
const metaString = typeof meta === "string" ? meta : meta?.__raw || "";
if (metaString.includes("showLineNumbers")) {
this.addClassToHast(node, "has-line-numbers");
}
return node;
},
};
}
Anschließend muss in der eigentlichen Config der astro.config.mjs beim Shiki-Teil der Transformator eingebunden werden:
export default defineConfig({
// ...
markdown: {
// ...
shikiConfig: {
themes: {
light: "github-light",
dark: "github-dark",
},
transformers: [shikiTransformerLineNumbers()],
},
},
// ...
});
Das Theming habe ich dabei direkt an GitHub angepasst. In dem Markdown fügt man dann noch das Attribut showLineNumbers hinzu:
```javascript showLineNumbers
function square(number) {
return number * number;
}
```
Somit können nun ganz einfach Codebeispiele mit Zeilennummern angelegt werden.