Tutorial WordPress: Estilizar bloques de código largos con scroll horizontal sutil

·

·

Introducción — por qué estilizar bloques de código largos

En blogs técnicos en WordPress es habitual pegar fragmentos de código que exceden el ancho del contenedor y rompen el diseño o hacen la lectura incómoda. La solución visual más elegante y usable es permitir scroll horizontal sutil en los bloques de código: que el lector pueda desplazarse cuando haga falta, que la pista de que hay más contenido sea discreta (sombras/fades) y que la experiencia sea accesible y funcione tanto en escritorio como en móvil.

Objetivos de este tutorial

Principio básico

El punto de partida es convertir el contenedor de código en un elemento con overflow-x: auto y white-space: pre (o el valor que use el resaltador), y luego añadir detalles: scrollbars finas, suavizado para iOS (-webkit-overflow-scrolling), y un indicativo visual (degradado/mask o pseudo-elementos) para sugerir que hay más contenido a la derecha/izquierda.

CSS base recomendado

Este bloque CSS crea un contenedor con scroll horizontal, scrollbars discretas y un fondo neutro. Pégalo en tu hoja de estilos del tema o en un archivo específico que enqueues para el frontend.

/ CSS base para bloques de código con scroll sutil /
.EnlighterJSRAW {
  position: relative                / necesario si usamos pseudo-elementos /
  display: block
  max-width: 100%
  overflow-x: auto                  / permite scroll horizontal /
  -webkit-overflow-scrolling: touch / smooth scrolling en iOS /
  white-space: pre                  / mantiene el formato del código /
  padding: 1rem                     / espacio interior /
  margin: 1rem 0
  border-radius: 8px
  background: linear-gradient(180deg, #0f1720, #0b1216) / tono oscuro neutro /
  color: #e6edf3
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Roboto Mono, monospace
  font-size: 0.95rem
  line-height: 1.5
  box-shadow: 0 1px 0 rgba(255,255,255,0.02) inset
  outline: none                     / el foco lo manejamos por accesibilidad abajo /
}

/ Scrollbars finas - WebKit /
.EnlighterJSRAW::-webkit-scrollbar {
  height: 8px
}
.EnlighterJSRAW::-webkit-scrollbar-track {
  background: transparent
}
.EnlighterJSRAW::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.06)
  border-radius: 999px
}

/ Compatibilidad con Firefox /
.EnlighterJSRAW {
  scrollbar-width: thin
  scrollbar-color: rgba(255,255,255,0.06) transparent
}

/ Indicador visual sutil por borde (fallback) /
.EnlighterJSRAW:focus {
  box-shadow: 0 0 0 3px rgba(100,150,255,0.12)
}

Degradado / máscara para indicar contenido oculto

Una solución moderna y muy elegante es usar mask-image (y -webkit-mask-image) para crear un fade en los bordes. Pero queremos que el fade desaparezca cuando no haya overflow o cambie según el scroll. Para eso combinamos una máscara por defecto y un script que añade clases cuando hay contenido oculto a la izquierda/derecha.

/ Por defecto: sutil fade a ambos lados /
.EnlighterJSRAW {
  -webkit-mask-image: linear-gradient(90deg, transparent 0px, black 24px, black calc(100% - 24px), transparent 100%)
  mask-image: linear-gradient(90deg, transparent 0px, black 24px, black calc(100% - 24px), transparent 100%)
  transition: -webkit-mask-image 200ms linear
  transition: mask-image 200ms linear
}

/ Si no hay overflow: eliminamos el fade para mejor contraste /
.EnlighterJSRAW.no-overflow {
  -webkit-mask-image: none
  mask-image: none
}

/ Si hay overflow sólo a la derecha: mostramos fade en la derecha /
.EnlighterJSRAW.can-scroll-right:not(.can-scroll-left) {
  -webkit-mask-image: linear-gradient(90deg, black 0%, black calc(100% - 24px), transparent 100%)
  mask-image: linear-gradient(90deg, black 0%, black calc(100% - 24px), transparent 100%)
}

/ Si hay overflow sólo a la izquierda: fade en la izquierda /
.EnlighterJSRAW.can-scroll-left:not(.can-scroll-right) {
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, black 24px, black 100%)
  mask-image: linear-gradient(90deg, transparent 0%, black 24px, black 100%)
}

JavaScript ligero para detectar overflow y scroll

Este pequeño script añade o quita clases .no-overflow, .can-scroll-left y .can-scroll-right en cada bloque. Usa ResizeObserver para reaccionar a cambios de tamaño (ventana o contenedor) y escucha el evento scroll. Envíalo en un archivo JS y enquéuelo en el frontend.

/ script: code-scroll.js /
(function () {
  var items = [].slice.call(document.querySelectorAll(.EnlighterJSRAW))

  if (!items.length) return

  function update(el) {
    var scrollLeft = el.scrollLeft
    var clientW = el.clientWidth
    var scrollW = el.scrollWidth

    el.classList.toggle(no-overflow, scrollW <= clientW   1)
    el.classList.toggle(can-scroll-left, scrollLeft > 0)
    el.classList.toggle(can-scroll-right, scrollLeft   clientW < scrollW - 1)
  }

  items.forEach(function (el) {
    // primera evaluación
    update(el)

    // al hacer scroll
    el.addEventListener(scroll, function () { update(el) }, { passive: true })

    // si el tamaño del contenedor cambia
    if (window.ResizeObserver) {
      var ro = new ResizeObserver(function () { update(el) })
      ro.observe(el)
    } else {
      // fallback: escucha resize de ventana
      window.addEventListener(resize, function () { update(el) })
    }
  })
})()

Markup de ejemplo (cómo debe aparecer el pre en tu HTML)

Si insertas código manualmente, añade tabindex=0 para que usuarios de teclado puedan desplazarse y para que el foco visual sea claro. En bloques generados por plugins de resaltado (Enlighter, Prism, Highlight.js, etc.) probablemente ya tengan un wrapper adapta las selectores si es necesario.


/ Tu código aquí /
.example { width: 1200px background: red }

Integración en WordPress: enqueue de CSS y JS

Coloca el CSS y JS anteriores en los archivos de tu tema (por ejemplo /css/code-scroll.css y /js/code-scroll.js) y regístralos/enquéualos desde functions.php.

/ functions.php /
function theme_enqueue_code_scroll() {
  wp_enqueue_style(theme-code-scroll, get_stylesheet_directory_uri() . /css/code-scroll.css, array(), 1.0)
  wp_enqueue_script(theme-code-scroll, get_stylesheet_directory_uri() . /js/code-scroll.js, array(), 1.0, true)
}
add_action(wp_enqueue_scripts, theme_enqueue_code_scroll)

/ Encolar también para el editor de bloques (Gutenberg) para ver el mismo estilo al editar /
function theme_enqueue_block_editor_assets_code_scroll() {
  wp_enqueue_style(theme-code-scroll-editor, get_stylesheet_directory_uri() . /css/code-scroll-editor.css, array(wp-edit-blocks), 1.0)
}
add_action(enqueue_block_editor_assets, theme_enqueue_block_editor_assets_code_scroll)

Soporte para el editor (Gutenberg / Classic)

1) Gutenberg: encolando una hoja de estilos para el editor (como en el ejemplo anterior) aseguras que los bloques de código dentro del editor reciban las mismas reglas visuales.

2) Classic editor: si tu plugin de resaltado imprime pre con la clase EnlighterJSRAW en el contenido, el CSS del frontend actuará igual. Si no, ajusta las selectores al HTML que genera tu plugin.

Accesibilidad y buenas prácticas

  • Teclado: asegúrate de que los bloques sean enfocables con tabindex=0 si no lo son por defecto. Al estar el foco, añade outline visible con CSS para indicar foco.
  • Screen readers: el código debe conservar su semántica (pre y code). No uses roles innecesarios que puedan confundir a lectores de pantalla.
  • Scroll suave en móviles: -webkit-overflow-scrolling: touch mejora la experiencia en iOS.
  • Evitar reflow pesado: el script propuesto es mínimo y usa ResizeObserver si está disponible, evitando cálculos frecuentes.

Compatibilidad y fallback

mask-image no funciona en navegadores antiguos. Por eso el CSS inicial funciona sin mask (simple scroll) y las reglas con mask-image son una mejora progresiva. Como fallback visual puedes usar pseudo-elementos con gradientes (antes de mask) si necesitas soporte más amplio.

Ejemplo de fallback con pseudo-elementos

/ Fallback: pseudo-elementos para crear fades si mask no está soportado /
.EnlighterJSRAW {
  position: relative
  overflow: auto
}

/ gradiente izquierdo /
.EnlighterJSRAW::before,
.EnlighterJSRAW::after {
  content: 
  pointer-events: none
  position: absolute
  top: 0
  height: 100%
  width: 32px
  transition: opacity 160ms linear
  opacity: 0 / visible sólo cuando corresponda /
}

/ izquierdo /
.EnlighterJSRAW::before {
  left: 0
  background: linear-gradient(90deg, rgba(11,17,22,1), rgba(11,17,22,0))
}

/ derecho /
.EnlighterJSRAW::after {
  right: 0
  background: linear-gradient(270deg, rgba(11,17,22,1), rgba(11,17,22,0))
}

/ se muestran según clases gestionadas por JS /
.EnlighterJSRAW.can-scroll-left::before { opacity: 1 }
.EnlighterJSRAW.can-scroll-right::after { opacity: 1 }

Tabla rápida de soporte y recomendaciones

Funcionalidad Soporte / nota
overflow-x:auto Universal — todos los navegadores modernos
scrollbar styling (::-webkit-scrollbar) WebKit/Blink (Chrome, Safari). Firefox usa scrollbar-width/scrollbar-color.
mask-image / -webkit-mask-image Chrome, Safari en Firefox la propiedad funciona pero con prefijos distintos usar pseudo-elementos como fallback.
ResizeObserver Soporte moderno si no está usar window.resize como fallback.

Buenas prácticas de publicación

  • Minimiza el CSS/JS que enqueues: agrupa en archivos y minifica para mantener velocidad.
  • Si usas plugins de resaltado (Enlighter, Prism, etc.), aplica tus reglas al wrapper que generan o añade una clase extra para no afectar otros elementos.
  • Prueba en móvil: comprueba que el scroll horizontal no interfiera con el scroll vertical general y que iOS desliza sin problemas.
  • Controla contraste: si tu fondo de código es oscuro, asegúrate de que las sombras/degradados no reduzcan demasiado la legibilidad.

Notas finales

Con combinar overflow-x: auto, scrollbars finas, una máscara o pseudo-elementos para el fade y un JS ligero para detectar overflow se obtiene una solución elegante, accesible y compatible. Integra el CSS y el JS en tu tema o plugin y registra también la hoja de estilos en el editor para mantener consistencia entre edición y publicación.



Leave a Reply

Your email address will not be published. Required fields are marked *