Saltar al contenido

Elegir tema y afinar shikiConfig

El resaltado de fábrica es un punto de partida, no una jaula. En markdown.shikiConfig eliges el tema con theme, montas un par claro/oscuro con themes, decides con defaultColor qué color se escribe en línea y cuál se deja a CSS, controlas el ajuste de línea con wrap y registras gramáticas propias con langs y langAlias. Afinar esa configuración es decidir la apariencia global del código sin escribir un solo estilo a mano.

theme: un tema para todo el sitio

El ajuste más directo es theme, que aplica un único tema a todos los bloques. Su valor puede ser el nombre de cualquiera de los temas que Shiki empaqueta —herederos de VS Code— o un objeto de tema completo si quieres uno propio.

JS
// astro.config.mjsimport { defineConfig } from 'astro/config';export default defineConfig({  markdown: {    shikiConfig: {      theme: 'dracula',    },  },});

El catálogo integrado es amplio: github-dark y github-light, dracula, nord, monokai, one-dark-pro, la familia catppuccin-*, y muchos más. Como un tema no es más que una tabla que mapea ámbitos de la gramática a colores, cambiarlo reescribe la paleta de todo el código sin tocar una sola línea de contenido. Y si ningún tema del catálogo te convence, theme acepta un objeto JSON con la misma forma que un tema de VS Code, de modo que puedes cargar el de tu editor y tener paridad exacta entre lo que escribes y lo que publicas.

themes y el par claro/oscuro

Un sitio moderno suele ofrecer modo claro y oscuro, y aquí theme se queda corto porque fija un solo color por token. La solución es themes, un objeto con al menos las claves light y dark. Cuando lo usas, Shiki no escribe un color fijo: emite, por cada token, un juego de variables CSS en línea —--shiki-light, --shiki-dark, y sus equivalentes de fondo --shiki-light-bg, --shiki-dark-bg—, de modo que una sola generación de HTML contiene los dos temas a la vez.

JS
// astro.config.mjsimport { defineConfig } from 'astro/config';export default defineConfig({  markdown: {    shikiConfig: {      themes: {        light: 'github-light',        dark: 'github-dark',      },    },  },});

La elegancia del truco está en que el trabajo caro —tokenizar el código, decidir qué es cada pieza— se hace una vez, y solo la decisión barata —qué columna de colores mostrar— se aplaza al cliente mediante CSS. El HTML es más pesado, porque lleva dos colores por token en lugar de uno, pero sigue sin llevar JavaScript: el cambio de tema es puro CSS sobre variables ya calculadas.

defaultColor, wrap y los ajustes finos

Con dos temas surge una pregunta: ¿cuál se ve si el navegador aún no ha aplicado ninguna clase de modo? Eso lo decide defaultColor. Su valor 'light' —el de fábrica— escribe además el color del tema claro como estilo en línea normal, para que el bloque se vea correctamente sin CSS alguno; 'dark' hace lo propio con el oscuro; y false no escribe ningún color por defecto, solo las variables, delegando por completo en tu CSS la elección. Poner defaultColor: false es la opción más limpia cuando controlas tú el cambio de modo, porque evita que un color por defecto compita con el que quieres imponer.

JS
shikiConfig: {  themes: { light: 'github-light', dark: 'github-dark' },  defaultColor: false,  wrap: true,},

Con defaultColor: false, el cambio de tema es una regla de CSS que selecciona qué variable gana según tu estrategia de modo oscuro. Basta con apuntar a la clase .astro-code y a sus <span> internos.

CSS
/* Modo claro por defecto: usa --shiki-light */.astro-code,.astro-code span {  color: var(--shiki-light);  background-color: var(--shiki-light-bg);}/* Cuando el documento entra en oscuro, cambia a --shiki-dark */html.dark .astro-code,html.dark .astro-code span {  color: var(--shiki-dark) !important;  background-color: var(--shiki-dark-bg) !important;}

El otro ajuste cotidiano es wrap, que gobierna las líneas largas. Con wrap: false —el valor por defecto— las líneas no se parten y el bloque muestra una barra de desplazamiento horizontal; con wrap: true las líneas se ajustan al ancho disponible y saltan de renglón; y con wrap: null Shiki no impone ningún estilo de desbordamiento, dejando que tu CSS decida por completo. La elección es de legibilidad: el desplazamiento preserva la forma exacta del código, el ajuste evita que el lector tenga que desplazarse pero rompe el alineado visual de las líneas.

langs y langAlias: lenguajes a medida

Shiki empaqueta cientos de gramáticas, pero a veces necesitas una que no está —un lenguaje de dominio propio, un formato de configuración raro— o quieres que un identificador inventado reutilice una gramática existente. Para lo primero está langs, un array donde registras gramáticas TextMate propias en forma de objeto JSON. Para lo segundo está langAlias, un mapa que hace que un nombre nuevo se comporte como un lenguaje ya conocido.

JS
shikiConfig: {  langs: [    // objeto de gramatica TextMate propio, cargado desde un JSON    miGramatica,  ],  langAlias: {    cjs: 'javascript',    conf: 'ini',    dockerfile: 'docker',  },},

Con ese langAlias, un bloque etiquetado como cjs se resalta con la gramática de JavaScript, y uno etiquetado conf con la de archivos ini. Es la forma barata de dar cobertura a nombres que tus lectores usarán aunque no sean identificadores oficiales, sin escribir ni mantener una gramática nueva. Y cuando de verdad necesitas describir un lenguaje que no existe en el catálogo, langs te deja añadirlo sin salir de la configuración, con la misma forma de gramática que entiende VS Code.