32. Exportación a HTML {#32-exportación-a-html}
HTML es el destino natural de Markdown: el formato se diseñó para escribir texto que luego se convertía en HTML. Es también el paso intermedio de casi todas las demás exportaciones (PDF con CSS, EPUB, correo, sitios estáticos).
Este capítulo explica cómo generar HTML limpio, completo, autocontenido y accesible, y cómo integrarlo en un sitio o en una aplicación.
32.1 Dos salidas distintas {#321-dos-salidas-distintas}
| Salida | Contenido | Uso |
|---|---|---|
| Fragmento | Solo el cuerpo convertido (<h1>, <p>…) |
Insertar en una plantilla, CMS o componente |
| Documento completo | <!DOCTYPE html>, <head>, <body>, CSS… |
Abrir directamente en el navegador o publicar |
En Pandoc, un fragmento es la opción por defecto; -s o --standalone genera el documento completo.
# Fragmento
pandoc README.md -f gfm -t html5 -o fragmento.html
# Documento completo con índice
pandoc README.md -f gfm -t html5 -s --toc -o README.html
# Documento autocontenido: CSS, imágenes y fuentes embebidas
pandoc README.md -f gfm -t html5 -s --embed-resources --standalone -o README.html
--embed-resources sustituye --self-contained, que está obsoleto. El resultado es un único archivo fácil de enviar por correo o publicar en un sitio sin dependencias.
32.2 Opciones útiles de Pandoc {#322-opciones-útiles-de-pandoc}
| Opción | Efecto |
|---|---|
--toc / --toc-depth=N |
Índice lateral o inicial y profundidad |
--number-sections |
Numera títulos (1, 1.1…) |
--section-divs |
Envuelve cada sección en <section id="…"> |
--id-prefix=prefijo- |
Evita colisiones de IDs al incrustar varios documentos |
--shift-heading-level-by=N |
Sube o baja todos los niveles de encabezado |
--css=estilo.css |
Añade una hoja de estilo |
--template=plantilla.html |
Usa una plantilla propia |
--highlight-style=estilo |
Cambia el tema de resaltado de código |
--no-highlight |
Desactiva el resaltado |
--mathjax, --katex, --mathml |
Renderiza matemáticas en el navegador |
--wrap=none |
No parte las líneas del HTML generado |
Ejemplo con secciones, numeración y prefijo:
pandoc manual.md -f gfm -t html5 -s \
--toc --toc-depth=3 --number-sections \
--section-divs --id-prefix=manual- \
--css=assets/manual.css \
-o manual.html
32.3 Plantillas {#323-plantillas}
Una plantilla HTML de Pandoc es un archivo con variables $…$:
<!DOCTYPE html>
<html lang="$lang$">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>$title$</title>
$for(css)$<link rel="stylesheet" href="$css$">$endfor$
</head>
<body>
<header>
<h1>$title$</h1>
$if(subtitle)$<p class="subtitle">$subtitle$</p>$endif$
</header>
$if(toc)$<nav id="TOC" aria-label="Índice">$toc$</nav>$endif$
<main>$body$</main>
$for(include-after)$
$include-after$
$endfor$
</body>
</html>
Variables habituales: $body$, $title$, $subtitle$, $author$, $date$, $lang$, $toc$, $css$, $header-includes$. La lista completa está en el manual de Pandoc.
pandoc README.md -s --template=plantilla.html -o README.html
32.4 CSS y presentación {#324-css-y-presentación}
El HTML generado por Pandoc usa clases estándar (sourceCode, code, footnotes, toc, table…). Un CSS mínimo debe cubrir:
- Tipografía: familia, tamaño, interlineado y medida de línea (entre 60 y 75 caracteres).
- Tablas:
border-collapse, cabeceras visibles y desplazamiento horizontal en pantallas pequeñas. - Código: fuente monoespaciada, fondo, borde y
overflow-x: auto. - Imágenes:
max-width: 100%yheight: auto. - Enlaces: color con contraste suficiente y subrayado.
- Modo oscuro:
@media (prefers-color-scheme: dark)con variables CSS.
:root { --texto: #1b1b1b; --fondo: #fff; --acento: #0b5cab; }
@media (prefers-color-scheme: dark) {
:root { --texto: #eae8e3; --fondo: #111318; --acento: #93c2ff; }
}
body {
max-width: 72ch;
margin: 0 auto;
padding: 2rem 1rem;
background: var(--fondo);
color: var(--texto);
font: 1rem/1.7 system-ui, sans-serif;
}
pre, table { overflow-x: auto; }
img { max-width: 100%; height: auto; }
32.5 Resaltado de sintaxis y matemáticas {#325-resaltado-de-sintaxis-y-matemáticas}
Pandoc genera HTML con clases para el resaltado (skylighting) y hojas de estilo integradas. Para cambiar el tema:
pandoc README.md -s --highlight-style=tango -o README.html
Temas disponibles: pygments, tango, espresso, zenburn, kate, monochrome, breezedark, haddock. También se puede generar un CSS propio:
pandoc --print-highlight-style=pygments > resaltado.css
Matemáticas:
pandoc apuntes.md -s --mathjax -o apuntes.html
pandoc apuntes.md -s --katex -o apuntes.html
pandoc apuntes.md -s --mathml -o apuntes.html
- MathJax: más completo (LaTeX, MathML, AsciiMath), pero pesado.
- KaTeX: más rápido, subconjunto de LaTeX.
- MathML: nativo del navegador, sin JavaScript; soporte y calidad variables.
El capítulo 41 detalla la sintaxis y las diferencias.
32.6 HTML seguro {#326-html-seguro}
Markdown permite HTML crudo. Si el contenido viene de terceros, no lo insertes sin sanitizar:
- Pandoc incluye el HTML tal cual; no lo sanea.
- markdown-it y marked permiten desactivar HTML (
html: false). - DOMPurify elimina scripts,
on*y URLs peligrosas en el navegador: https://github.com/cure53/DOMPurify. - En un servidor, sanitiza también y aplica una Content Security Policy.
import MarkdownIt from "markdown-it";
import DOMPurify from "dompurify";
const md = new MarkdownIt({ html: false, linkify: true });
const html = DOMPurify.sanitize(md.render(texto));
Riesgos típicos: <script>, javascript: en enlaces, <iframe> incrustados, imágenes de seguimiento y CSS que oculta contenido. Véase el capítulo 48.
32.7 Otras herramientas {#327-otras-herramientas}
| Herramienta | Lenguaje | Uso |
|---|---|---|
| markdown-it | JavaScript | Renderizado extensible; plugins de anclas, notas y tablas |
| marked | JavaScript | Rápido y sencillo; CLI y API |
| cmark | C | Implementación de referencia de CommonMark |
| cmark-gfm | C | CommonMark + extensiones de GitHub |
| Python-Markdown | Python | Extensiones de tablas, notas, TOC y metadatos |
| kramdown | Ruby | Motor de Jekyll; IAL y atributos |
| remark / rehype | JavaScript | Pipeline de AST y plugins |
# markdown-it
npx markdown-it README.md -o README.html
# marked
npx marked -i README.md -o README.html
# cmark
cmark --to html README.md > README.html
# Python-Markdown
python -m markdown README.md > README.html
# kramdown
kramdown README.md > README.html
32.8 HTML dentro de generadores de sitios {#328-html-dentro-de-generadores-de-sitios}
Los generadores estáticos (Jekyll, Hugo, MkDocs, Docusaurus, Eleventy) convierten Markdown a HTML y añaden plantillas, navegación y búsqueda. En ellos:
- El Front Matter aporta título, fecha, plantilla y metadatos.
- Los enlaces internos deben apuntar a la URL final (
.html, rutas limpias o slugs). - Las extensiones del generador pueden cambiar la sintaxis (por ejemplo, shortcodes o includes).
- El HTML crudo puede estar deshabilitado por seguridad.
Véase el capítulo 28.
32.9 Verificación {#329-verificación}
- Validez: https://validator.w3.org/.
- Accesibilidad: https://pa11y.org/ o Lighthouse en las herramientas del navegador.
- Enlaces: comprueba anclas y rutas relativas con un verificador.
- Rendimiento: evita imágenes enormes y JavaScript innecesario.
- Sin JavaScript: el contenido debe seguir siendo legible.
# Servir el resultado en local
python -m http.server 8000
32.10 Lista de comprobación {#3210-lista-de-comprobación}
- ¿Fragmento o documento completo? Es una decisión consciente.
- El
<html>declara el idioma (lang="es"). - Hay
<meta charset="utf-8">y<meta name="viewport">. - El título de la página es descriptivo.
- Los encabezados no saltan niveles.
- Las tablas tienen cabeceras y no desbordan.
- Las imágenes tienen
alty dimensiones razonables. - El HTML de terceros está sanitizado.
- El resultado se ve bien en claro, oscuro y móvil.
- Los enlaces internos y el índice funcionan.