Themes

On this page

Themes

Themes sind native BoxLang-.bxm-Templates - es gibt keine separate Template-Engine oder einen eigenen Build-Schritt.

Integriert

ThemeBasisHinweise
bootstrap (Standard)Bootstrap 5, vendoriertPoppins-Schriftart, Navbar mit Marken-Gradient
materialHandgefertigtes Material-artiges CSSCard-Layout, Elevation-Schatten, Roboto-Schriftart
tailwindTailwind Play CDNUtility-Class-getrieben, kein Build-Schritt

Das eigene CSS/JS jedes integrierten Themes (Bootstraps CSS/JS-Bundle, highlight.js, Alpine.js, lunr.js für den standardmäßigen local-Suchanbieter, und Mermaid, wenn mermaid aktiviert ist) wird vendoriert mit diesem Modul ausgeliefert und direkt in jede gebaute site/ kopiert - kein CDN, kein Internetzugang nötig, um eine gebaute Website anzusehen. Die eigene Utility-Engine des tailwind-Themes (ein clientseitiger JIT-Compiler, kein statisches Stylesheet) und andere optionale Funktionen, die du selbst aktivierst (math, Algolia-Suche, Google Analytics), laden weiterhin von einem CDN oder einer gehosteten API - siehe Air-gapped/Offline-Websites unten.

Alle drei verwenden dieselbe BoxLang-Markenpalette: einen #00FF78 -> #00DBFF-Gradient und einen #FFF500-Akzent - und alle drei bringen denselben Satz an Seitenfunktionen mit:

  • Ein Inhaltsverzeichnis "Auf dieser Seite", erzeugt aus den eigenen h2/h3-Überschriften jeder Seite.
  • Breadcrumbs, die die Ahnenkette einer Seite zeigen, wenn sie mehr als eine Ebene tief unter einem verlinkten Vorfahren verschachtelt ist.
  • Vorherige/Nächste-Seite-Links am Ende des Artikels, entlang der eigenen Leserichtung der Navigation.
  • Syntax-hervorgehobene Codeblöcke, über highlight.js plus eine eigene BoxLang-Grammatik (```bx/```boxlang/```cfscript), jeweils mit einem Kopieren-Button - bei Hover sichtbar auf Geräten, die das unterstützen, auf Touch-Geräten immer sichtbar (dort gibt es kein Hover, um ihn einzublenden). Siehe Markdown-Erweiterungen.
  • Selbst gehostete Webfonts - keine Anfrage an fonts.googleapis.com zur Anzeigezeit.
  • Ein Dunkel-/Hell-Modus-Umschalter, angetrieben von Alpine.js für die Reaktivität. Die Wahl des Besuchers wird in localStorage gemerkt (mit Fallback auf die Betriebssystem-Präferenz) und noch vor dem ersten Rendern angewendet, um ein kurzes Aufblitzen des falschen Themes zu vermeiden.
  • Eine responsive Kopfzeile, die bei jeder Breite einreihig bleibt - ein schmales Viewport schrumpft die Suchbox, statt sie in eine eigene Zeile umbrechen zu lassen - plus eine einklappbare Sidebar-Navigation (ein Hamburger-Umschalter in bootstrap/material/tailwind gleichermaßen).
  • Tastaturkürzel in der Suchbox: / fokussiert die Suche von überall auf der Seite, und Escape schließt die Ergebnisse. Siehe Suche.
  • Ein Repo-Link und eine "Diese Seite bearbeiten"-/"Zuletzt aktualisiert"-Zeile, wenn die Optionen repo/lastUpdated in bxsites.json gesetzt sind. Siehe Konfiguration.
  • Ein "Markdown herunterladen"-Link, neben "Diese Seite bearbeiten" - die rohe .md-Quelle jeder Seite wird zusammen mit ihrem gebauten HTML veröffentlicht (guides/themes.md liegt neben guides/themes/index.html), sodass sie (oder eine KI) die Seite direkt als reines Markdown lesen kann, statt gerendertes HTML zu parsen. Immer aktiv, keine Konfiguration nötig. Siehe Erste Schritte.
  • Eine optionale Fußzeile (Copyright, social-Links, ein "Built with BX Sites"-Hinweis), wenn footer in bxsites.json true ist. Siehe Konfiguration.
  • Ein Versionsumschalter, der automatisch erscheint, sobald ein Projekt einen docs/versions/-Ordner mit mehr als einer Version hat. Siehe Konfiguration.
  • Eine themenspezifische 404.html, automatisch ausgeliefert von den meisten statischen Hosts (einschließlich GitHub Pages) für jeden nicht gefundenen Pfad.
  • Ein eigenes Logo und Favicon, wenn theme.logo/theme.favicon in bxsites.json gesetzt sind. Siehe Konfiguration.
  • Eine einklappbare Sidebar-Navigation, opt-in über theme.options.navCollapsible. Siehe Konfiguration.
  • Google Analytics, wenn analytics in bxsites.json konfiguriert ist. Siehe Konfiguration.
  • Social-Share-Cards (Open-Graph- + Twitter-Card-Meta-Tags), erzeugt aus der description-Frontmatter jeder Seite (oder der websiteweiten description) und ihrem eigenen ogImage (oder dem websiteweiten) - optional automatisch pro Seite erzeugt über generateOgImages in bxsites.json. Siehe Konfiguration.
  • Seiten-Tags, ein Icon und eine Zusammenfassungszeile, alle opt-in über die eigene Frontmatter einer Seite - Tags werden als Badges gerendert, die zu einem websiteweiten /tags/-Index verlinken. Siehe Erste Schritte.
  • Eine explizite Navigations-Überschreibung, in bxsites.json oder der eigenen docs/nav.json, die die Ordner-Ableitung für große Websites ersetzt. Siehe Konfiguration.
  • Zusätzliches CSS/JS, eingebunden über extraCss/extraJs in bxsites.json. Siehe Konfiguration.
  • Admonition-Callout-Boxen (Hinweis/Warnung/Tipp/...), standardmäßig im Markdown jeder Seite aktiv, einschließlich einklappbarer Varianten - keine Konfiguration nötig. Siehe Markdown-Erweiterungen.
  • Fußnoten und Definitionslisten, opt-in über markdown in bxsites.json. Siehe Markdown-Erweiterungen.
  • Content-Tabs, Code-Zeilennummern/hervorgehobene Zeilen/Titel und Diff-Markierungen/Terminal-Rahmen für Codeblöcke, keine Konfiguration nötig. Siehe Markdown-Erweiterungen.
  • Mermaid-Diagramme, opt-in über mermaid in bxsites.json. Siehe Markdown-Erweiterungen.
  • Mathematik (KaTeX), opt-in über math in bxsites.json. Siehe Markdown-Erweiterungen.

Lege in bxsites.json fest, welches Theme ein Projekt verwendet:

{ "theme": { "name": "material" } }

Air-gapped/Offline-Websites

Eine gebaute Website funktioniert standardmäßig völlig ohne Internetzugang, für die Themes bootstrap und material mit dem standardmäßigen local-Suchanbieter: Bootstraps eigenes CSS/JS, highlight.js, Alpine.js und lunr.js sind alle mit diesem Modul vendoriert (resources/assets/vendor/) und werden zur Build-Zeit direkt nach site/assets/vendor/ kopiert - nirgends im erzeugten HTML taucht dafür ein CDN-<script>-/<link>-Tag auf. Aktivierst du den Schlüssel mermaid in bxsites.json, wird Mermaid auf dieselbe Weise vendoriert - sein mermaid.min.js-Bundle wird nach site/assets/vendor/mermaid/ kopiert, und jedes integrierte Theme lädt es von dort, sodass Diagramme weiterhin ganz ohne ausgehende Anfragen gerendert werden.

Ein paar Dinge greifen weiterhin nach außen ins Netzwerk, aber nur, wenn du sie selbst aktivierst:

  • Die eigene Utility-Engine des tailwind-Themes ist ein clientseitiger JIT-Compiler, geladen von cdn.tailwindcss.com - kein statisches Stylesheet, das dieses Modul auf dieselbe Weise vendorieren könnte, daher ist dieses Theme (noch) nicht air-gapped-fähig.
  • Mermaids eigene Layout-Engine lädt bei Bedarf einen zusätzlichen Chunk nach, elk-api.js, von jsDelivr - aber nur für Diagrammtypen, die den elk-Layout-Algorithmus verwenden; das vendorierte mermaid.min.js rendert jeden anderen Diagrammtyp vollständig eigenständig.
  • Die Option math in bxsites.json lädt KaTeX (sowohl dessen JS als auch die eigenen Font-Dateien) von einem CDN, wenn sie aktiviert ist.
  • searchProvider.provider: "algolia" und analytics.provider: "google" sprechen naturgemäß mit einer gehosteten API/einem Tracking-Endpunkt - das Vendorieren der JS-Datei würde diese Abhängigkeit nicht beseitigen.

Wenn dein Einsatzziel wirklich null Internetzugang hat, bleib bei bootstrap/material, dem standardmäßigen local-Suchanbieter, vermeide elk-Layout-Mermaid-Diagramme, falls mermaid aktiviert ist, und lass math/Algolia/Analytics aus.

Icons

Die eigene icon-Frontmatter einer Seite (angezeigt neben ihrem Titel und neben ihrem Eintrag in der Sidebar-Navigation) akzeptiert entweder ein reines Emoji/einen kurzen Text - die ursprüngliche, weiterhin vollständig unterstützte Form - oder ein benanntes Icon aus einer von acht selbst gehosteten Bibliotheken, alle MIT-/ISC-lizenziert und mit diesem Modul mitgeliefert (~16.200 Icons insgesamt, kein CDN, kein zusätzliches Gewicht für eine gebaute Seite über die tatsächlich verwendete Handvoll Icons hinaus - siehe IconResolver.bx):

---
icon: rocket
---
---
icon: lucide:rocket
---
---
icon: phosphor-bold:rocket
---

Ein reines rocket verwendet standardmäßig Phosphor, reguläre Stärke. Phosphor liefert alle sechs eigenen Stärken, jede mit eigenem Präfix: phosphor-thin:, phosphor-light:, phosphor: (regulär, identisch mit dem reinen Namen), phosphor-bold:, phosphor-fill: und phosphor-duotone:. Stelle lucide: voran für Lucide, oder tabler: für Tabler. Durchsuche die jeweilige eigene Galerie der Website nach dem exakten Namen - er stimmt genau mit dem vendorierten Dateinamen dieses Moduls überein (Kleinbuchstaben, mit Bindestrichen, z. B. book-open, arrow-up-right; Phosphors eigene Website zeigt einen Stärke-Umschalter - jede ihrer sechs Optionen dort entspricht einem der sechs phosphor[-weight]:-Präfixe dieses Moduls).

Font Awesome ist bewusst nicht dabei - sein Duotone-Stil (und der Großteil seines Icon-Sets ab v6) ist Pro-only, nicht unter einer Lizenz verfügbar, unter der dieses Modul sie kostenlos bündeln und weiterverbreiten könnte.

Auch eine eigene SVG-Datei eines Projekts funktioniert - lege sie unter docs/assets/icons/my-icon.svg ab und referenziere sie als icon: custom:my-icon.

Ein nav.json-Eintrag kann ebenfalls ein eigenes icon setzen, das die eigene Frontmatter der Zielseite für genau diesen einen Eintrag überschreibt:

{ "title": "Guides", "path": "guides/index.md", "icon": "lucide:book-open" }

Der ThemeProvider-Vertrag

Ein Theme ist einfach ein Ordner mit:

  • layout.bxm (erforderlich) - die äußere HTML-Hülle + Navigation. Erhält variables.page, variables.nav, variables.siteConfig, variables.themeDir und variables.basePath im Scope, und bindet das benachbarte page.bxm über #variables.themeDir#/page.bxm ein. variables.basePath ist immer ein root-relativer, auf / endender Pfad (standardmäßig /, /my-docs/, wenn baseURL in bxsites.json das überschreibt) - stelle diesen jedem internen href/src voran, statt ein führendes / fest zu codieren, damit das Theme auch funktioniert, wenn die Website aus einem Unterpfad ausgeliefert wird.
  • page.bxm (erforderlich) - der Artikelinhalt. Rendert variables.page.contentHtml - das bereits konvertierte Markdown.
  • search.bxm (optional) - das Markup der Suchbox, von layout.bxm nur eingebunden, wenn search in bxsites.json true ist. Siehe Suche.
  • assets/ (optional) - Theme-CSS/JS, zur Build-Zeit nach site/assets/theme/ kopiert.

variables.page.editUrl/.lastUpdated (leere Zeichenketten, wenn nicht konfiguriert) und variables.siteConfig.repo/.social/.footer sind ebenfalls immer verfügbar und stützen die oben beschriebenen Repo-Link-/Bearbeiten-Link-/Zuletzt-aktualisiert-/Fußzeilen-Funktionen - ein eigenes Theme entscheidet selbst, ob und wie es sie rendert, wie auch alles andere. variables.versions ([ { label, url } ], "Latest" zuerst) und variables.currentVersion (das gerade gerenderte label) stützen den Versionsumschalter - leer/"Latest" für ein nicht versioniertes Projekt, sodass ein Theme nur dann einen Umschalter rendern muss, wenn variables.versions.len() gt 1. Die drei integrierten Themes beziehen ihre Repo-/Social-Icons aus einem kleinen gemeinsamen SVG-Lookup, <bx:include template="#variables.moduleAssetsDir#/icons.bxm"> (definiert bxsitesIcon( name ), eines von github, twitter/x, rss, youtube, linkedin, facebook, bluesky, threads, slack, patreon, email, edit, clock, mit einem generischen Link-Symbol als Fallback) - ein eigenes Theme kann das auf dieselbe Weise einbinden, oder seine Icons vollständig selbst bereitstellen.

Ein Theme-Ordner, dem eine der beiden erforderlichen Dateien fehlt, schlägt sofort mit einem klaren BxSites.InvalidTheme-Fehler zur Build-Zeit fehl, statt mit einem verwirrenden Template-Fehler tief im Rendering.

Farben anpassen, ohne ein Theme zu überschreiben

Für eine kleine Farb-/Schriftanpassung ist ein ganzes Theme zu forken Overkill - jedes integrierte Theme liest seine Palette aus einer Handvoll CSS-Custom-Properties auf :root, erneut deklariert unter [data-theme="dark"] für den Dunkelmodus. Das extraCss von bxsites.json wird nach dem eigenen Stylesheet des Themes geladen, sodass eine erneute Deklaration mit gleicher Spezifität darin gewinnt, ohne resources/themes/ überhaupt anzurühren:

{ "extraCss": [ "assets/brand.css" ] }
/* docs/assets/brand.css - copied to site/assets/brand.css at build time */
:root {
	--bxsites-gradient-start: #7C3AED;
	--bxsites-gradient-end: #DB2777;
	--bxsites-accent: #FBBF24;
	--bxsites-link: #7C3AED;
	--bxsites-link-hover: #9F5AF0;
}

[data-theme="dark"] {
	--bxsites-link: #C4B5FD;
	--bxsites-link-hover: #DDD6FE;
}

Das eigene Set des bootstrap-Themes (resources/themes/bootstrap/assets/style.css) besteht aus --bxsites-gradient-start/-end, --bxsites-accent, --bxsites-bg, --bxsites-text, --bxsites-sidebar-bg, --bxsites-sidebar-text, --bxsites-border, --bxsites-link, --bxsites-link-hover und --bxsites-code-bg - material und tailwind folgen derselben --bxsites-*-Namensgebung mit ihren eigenen kleinen Abweichungen. Alles über Farbe/Schriftart hinaus (Layout, Chrome hinzufügen/entfernen) braucht eine echte Überschreibung oder ein eigenes Theme - siehe unten.

Ein Theme überschreiben

Lege deine eigenen layout.bxm + page.bxm (und optional search.bxm / assets/) in einen theme/-Ordner im Wurzelverzeichnis deines Projekts. BX Sites bevorzugt eine projektweite theme/-Überschreibung gegenüber jedem integrierten Theme, solange sie den obigen Vertrag erfüllt - die integrierten Themes unter resources/themes/ dieses Moduls sind ein guter Ausgangspunkt zum Kopieren und Anpassen.

Ein durchgearbeitetes Beispiel - starte mit bootstrap und tausche seine Markenpalette und Überschriften-Schriftart gegen deine eigenen aus, wobei alles andere (Navigation, Suche, Dunkelmodus, Code-Hervorhebung, ...) genau so weiterläuft, wie es bereits funktioniert:

my-project/
├── bxsites.yaml
├── docs/
└── theme/                    ← project-level override, checked before any built-in theme
    ├── layout.bxm             ← copied from resources/themes/bootstrap/layout.bxm
    ├── page.bxm                ← copied from resources/themes/bootstrap/page.bxm, unchanged
    ├── search.bxm               ← copied unchanged
    └── assets/
        └── style.css              ← copied from bootstrap's assets/style.css, then edited
  1. Kopiere die drei .bxm-Dateien und assets/style.css aus resources/themes/bootstrap/ dieses Moduls in das theme/ deines Projekts.

  2. Ändere nur das, was du wirklich ändern musst. Um Markenpalette und Schriftart zu tauschen, genügt der obere Teil von theme/assets/style.css:

    :root {
    	--bxsites-gradient-start: #7C3AED;  /* was #00FF78 */
    	--bxsites-gradient-end: #DB2777;    /* was #00DBFF */
    	--bxsites-accent: #FBBF24;          /* was #FFF500 */
    }
    
    body {
    	font-family: "Inter", system-ui, sans-serif;  /* was "Poppins" */
    }
    
  3. Führe bxSites build aus (oder serve während der Iteration) - BX Sites übernimmt theme/ automatisch, keine Änderung an bxsites.json nötig (ein projektweiter theme/-Ordner hat immer Vorrang vor dem im theme.name genannten integrierten Theme). Alles, was du nicht angefasst hast - Navigations-Rendering, Suche, der Dunkelmodus-Umschalter, Code-Annotationen - funktioniert genau so weiter, wie es im ursprünglichen bootstrap-Theme funktioniert hat, da es darunter immer noch genau dasselbe layout.bxm/page.bxm-Markup ist.

Ein projektweiter theme/-Ordner ist allerdings alles-oder-nichts - sobald BX Sites einen findet, wird er anstelle des integrierten Themes vollständig verwendet, braucht also trotzdem seine eigenen layout.bxm + page.bxm, selbst wenn du nur assets/style.css geändert hast (ein Ordner, dem eine der beiden fehlt, schlägt sofort mit BxSites.InvalidTheme fehl, statt stillschweigend zurückzufallen). Für eine reine CSS-Anpassung ohne .bxm, nutze stattdessen extraCss von oben - es legt sich über das Theme, das bxsites.json benennt, ganz ohne theme/-Ordner. theme/ ist für den Fall, dass du auch das Markup selbst ändern musst, siehe als Nächstes.

Ein Theme von Grund auf schreiben

Ein Theme braucht nur die beiden erforderlichen Dateien, hier also ein wirklich minimales Beispiel - kein Bootstrap/Tailwind, kein Dunkelmodus, keine Such-UI - um genau zu zeigen, was erforderlich ist im Vergleich zu dem, was die integrierten Themes zusätzlich bieten. Speichere beide als theme/layout.bxm und theme/page.bxm in deinem Projekt - ein projektweiter theme/-Ordner wird automatisch übernommen (wie oben), keine Änderung an bxsites.json nötig:

<!-- theme/layout.bxm -->
<bx:script>
	function renderNav( required array nodes ) {
		var html = "<ul>"
		for ( var node in arguments.nodes ) {
			html &= "<li>"
			html &= len( node.url )
				? '<a href="' & variables.basePath & node.url & '">' & encodeForHTML( node.title ) & '</a>'
				: encodeForHTML( node.title )
			if ( node.children.len() ) {
				html &= renderNav( node.children )
			}
			html &= "</li>"
		}
		return html & "</ul>"
	}
</bx:script>
<bx:output>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>#encodeForHTML( variables.page.title )# - #encodeForHTML( variables.siteConfig.name )#</title>
	<link rel="stylesheet" href="#variables.basePath#assets/theme/style.css">
</head>
<body>
	<header><a href="#variables.basePath#">#encodeForHTML( variables.siteConfig.name )#</a></header>
	<nav>#renderNav( variables.nav )#</nav>
	<main>
</bx:output>
<bx:include template="#variables.themeDir#/page.bxm">
<bx:output>
	</main>
</body>
</html>
</bx:output>
<!-- theme/page.bxm -->
<bx:output>
<article>
	<h1>#encodeForHTML( variables.page.title )#</h1>
	#variables.page.contentHtml#
</article>
</bx:output>

Das ist ein vollständiges, funktionierendes Theme - variables.page.contentHtml ist das bereits konvertierte Markdown (Syntax-Hervorhebung, Admonitions, Tabs, Mathematik und alles), es bleibt also nichts mehr zu parsen, nur noch zu layouten. Von hier aus füge hinzu, was die integrierten Themes haben und du tatsächlich willst: search.bxm (nur eingebunden, wenn search in bxsites.json true ist

  • siehe Suche), einen Dunkelmodus-Umschalter (kopiere das x-data/x-init-Alpine.js-Paar vom <body>-Tag von resources/themes/bootstrap/layout.bxm und den passenden [data-theme="dark"]-CSS-Block), Breadcrumbs/Tags/Vorherige-Nächste-Links (page.bxm in jedem integrierten Theme zeigt das Muster - jedes ist nur ein if um eine kleine Render-Funktion, alle gespeist aus Feldern, die bereits auf variables.page vorhanden sind), oder einen assets/-Ordner für dein eigenes CSS/JS, automatisch zur Build-Zeit nach site/assets/theme/ kopiert.
Edit this page Download Markdown Last updated Aug 23, 2026, 2:17:28 AM