Tutorial WordPress: Hacer que los enlaces externos muestren un icono automático con CSS mask

·

·

Introducción

Este tutorial explica paso a paso cómo mostrar automáticamente un icono al lado de los enlaces externos en un sitio WordPress usando CSS mask. La técnica aprovecha pseudo-elementos y máscaras SVG para dibujar un icono coloreable por CSS (usando currentColor) sin añadir imágenes adicionales al DOM ni depender de fuentes de iconos. Incluyo varias opciones: selector CSS puro, mejora con PHP en functions.php para añadir clases y etiquetas accesibles, y un pequeño fallback/ajuste para navegadores.

Por qué usar CSS mask

Resumen de enfoques

  1. Solo CSS: reconocer enlaces externos por selector y añadir ::after con mask.
  2. WordPress (recomendado): añadir clase external a enlaces externos desde functions.php y, opcional, insertar una etiqueta con texto para lectores de pantalla.
  3. Fallback JS: en caso de que queramos soportar selecciones más complejas o navegadores muy antiguos.

Nota importante sobre dominio

En los ejemplos CSS con selectores que excluyen tu dominio, sustituye tudominio.com por el dominio real de tu sitio (sin protocolo).

1) Icono SVG: dos opciones (archivo o data URI)

Puedes usar un archivo SVG en tu theme (por ejemplo: /wp-content/themes/tu-tema/images/external.svg) o incrustarlo como data URI en la propiedad mask. Aquí un SVG simple (símbolo de flecha externa) para usar/convertir:

ltsvg xmlns=http://www.w3.org/2000/svg viewBox=0 0 24 24 fill=none stroke=currentColor stroke-width=2 stroke-linecap=round stroke-linejoin=roundgt
  ltpath d=M18 13v6a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6 /gt
  ltpolyline points=15 3 21 3 21 9 /gt
  ltline x1=10 y1=14 x2=21 y2=3 /gt
lt/svggt

Si prefieres el data URI, tendrás que escapar/URL-encodar el SVG para insertarlo en CSS. Para simplificar el tutorial usaré un data URI abreviado en los ejemplos, pero puedes señalar al archivo SVG externo para un caché más eficiente.

2) CSS: selector puro (sin PHP)

Este CSS añade un icono a los enlaces que empiezan por http/https y que no contienen tu dominio. Sustituye tudominio.com por tu dominio real.

/ Selector que detecta enlaces externos (reemplaza tudominio.com) /
a[href^=http]:not([href=tudominio.com]) {
  / opcional: estilos del enlace /
}

/ Añade el icono usando un pseudo-elemento y máscara SVG /
a[href^=http]:not([href=tudominio.com])::after {
  content: 
  display: inline-block
  width: 0.9em
  height: 0.9em
  margin-left: 0.3em
  vertical-align: text-bottom
  background-color: currentColor              / color del icono igual que el texto /
  background-repeat: no-repeat
  background-position: center
  background-size: contain

  / Máscara (para navegadores modernos) - ejemplo usando data URI SVG /
  -webkit-mask: url(data:image/svg xmlutf8,) no-repeat center / contain
  mask: url(data:image/svg xmlutf8,) no-repeat center / contain

  / No interacciones en el icono /
  pointer-events: none
}

/ Pequeño ajuste para enlaces dentro de texto pequeño /
a[href^=http]:not([href=tudominio.com])::after {
  transform: translateY(0.06em)
}

Explicación rápida

  • background-color: currentColor permite que el icono tome el color del enlace.
  • -webkit-mask y mask usan la misma imagen SVG. Mantén ambos para compatibilidad con Safari y Chrome.
  • pointer-events: none evita que el pseudo-elemento interfiera en el clic del enlace.

3) Mejor método para WordPress: añadir clase y etiqueta accesible desde functions.php

Es recomendable que la lógica de detectar enlaces externos se haga en el servidor (functions.php) y que se inserte una clase external en esos enlaces. Así el CSS queda limpio y el selector no necesita comprobar el dominio en cliente. Además añadiremos una etiqueta (enlace externo) dentro del enlace para lectores de pantalla.

/
  Añade clase .external, target=_blank, rel=noopener noreferrer y un texto accesible
  a los enlaces externos dentro del contenido.
  Colocar en functions.php del tema hijo.
 /
function mi_tema_marcar_enlaces_externos( content ) {
    site_host = parse_url( home_url(), PHP_URL_HOST )
    libxml_use_internal_errors(true)

    dom = new DOMDocument()
    // envuelve el contenido para que DOMDocument lo trate bien
    dom->loadHTML(
. content .
) xpath = new DOMXPath( dom ) foreach ( xpath->query(//a[@href]) as a ) { href = a->getAttribute(href) // considerar solo http/https if ( preg_match(#^https?://#i, href) ) { href_host = parse_url( href, PHP_URL_HOST ) if ( href_host stripos( href_host, site_host ) === false ) { // añadir clase external existing_class = a->getAttribute(class) a->setAttribute(class, trim(existing_class . external)) // asegurarse de target y rel if ( ! a->hasAttribute(target) ) { a->setAttribute(target, _blank) } a->setAttribute(rel, noopener noreferrer) // añadir texto accesible dentro del enlace (visualmente oculto pero disponible a lectores) sr = dom->createElement(i, (enlace externo)) // la etiqueta está permitida sr->setAttribute(class, sr-only) a->appendChild( sr ) } } } // extraer contenido interior del wrapper div div = dom->getElementsByTagName(div)->item(0) new_content = foreach ( div->childNodes as child ) { new_content .= dom->saveHTML( child ) } return new_content } add_filter( the_content, mi_tema_marcar_enlaces_externos, 20 )

Notas sobre el snippet PHP

  • Funciona con el contenido procesado por the_content. Si necesita aplicarse también a widgets/textos en otras áreas, añada filtros adicionales.
  • Libxml errores se suprimen para evitar ruidos en el log usar con cuidado si tu HTML es muy irregular.

4) CSS final asociado a la clase .external y estilos para .sr-only

Con el PHP anterior, los enlaces externos tendrán la clase external. Así el CSS queda más claro y fácil de mantener.

/ Icono para enlaces marcados por PHP /
a.external::after {
  content: 
  display: inline-block
  width: 0.9em
  height: 0.9em
  margin-left: 0.3em
  vertical-align: text-bottom
  background-color: currentColor

  -webkit-mask: url(/wp-content/themes/tu-tema/images/external.svg) no-repeat center / contain
  mask: url(/wp-content/themes/tu-tema/images/external.svg) no-repeat center / contain

  pointer-events: none
}

/ Estilos para el texto accesible añadido () /
.sr-only {
  position: absolute !important
  width: 1px
  height: 1px
  padding: 0
  margin: -1px
  overflow: hidden
  clip: rect(0 0 0 0)
  clip-path: inset(50%)
  border: 0
  white-space: nowrap
}

5) Fallback y compatibilidad

  • Si usas archivo SVG externo, el navegador lo cacheará — recomendado para producción.
  • Para navegadores que no soportan mask, puedes ofrecer un fallback sencillo usando background-image con la misma SVG (aunque no será fácilmente coloreable). Por ejemplo:
    / Fallback simple: fondo con SVG (no recolorable) /
    a.external.no-mask::after {
      background-image: url(/wp-content/themes/tu-tema/images/external.svg)
      background-size: contain
      background-repeat: no-repeat
    }
        
  • Safari y Chrome requieren -webkit-mask en muchos casos, por eso se añaden ambos prefijos.

6) Variante con JavaScript (opcional)

Si prefieres añadir la clase en cliente (por ejemplo, si no puedes editar functions.php), puedes usar un pequeño script que añada la clase external para todos los enlaces externos al cargar la página.

// Ejecutar en footer o en un archivo JS cargado al final
(function(){
  var siteHost = location.host
  var links = document.querySelectorAll(a[href^=http])
  for (var i = 0 i < links.length i  ) {
    var a = links[i]
    try {
      var hrefHost = new URL(a.href).host
      if (hrefHost  hrefHost.indexOf(siteHost) === -1) {
        a.classList.add(external)
        if (!a.hasAttribute(target)) a.setAttribute(target,_blank)
        a.setAttribute(rel,noopener noreferrer)
        // añadir texto accesible si lo necesitas:
        var iEl = document.createElement(i)
        iEl.className = sr-only
        iEl.textContent =  (enlace externo)
        a.appendChild(iEl)
      }
    } catch(e) { / ignore invalid URLs / }
  }
})()

7) Consideraciones de accesibilidad y SEO

  • Para usuarios de lectores de pantalla añadimos un texto accesible (enlace externo) dentro del enlace, oculto visualmente con .sr-only.
  • Añadir target=_blank debe acompañarse de rel=noopener noreferrer por seguridad y rendimiento.
  • Evita usar solo CSS generated content para texto informativo, ya que los lectores de pantalla pueden no leer contenido generado por CSS por eso el enfoque PHP/JS inserta texto real dentro del enlace.

8) Recomendaciones finales

  1. En entorno de producción usa la variante PHP (functions.php) o un plugin para modificar el contenido del servidor. Es más fiable y evita depender de JS.
  2. Usa SVG externo para cache y rendimiento. Usa data URI solo para pruebas o en casos concretos.
  3. Prueba en distintos navegadores (Safari, Chrome, Firefox) porque el soporte de mask puede variar incluye -webkit-mask para compatibilidad con WebKit.
  4. Ten cuidado con el parseo HTML en PHP: la función con DOMDocument funciona bien en contenido típico pero revisa en páginas con HTML muy fragmentado.

Recursos útiles

Conclusión

Con una combinación de un pequeño ajuste en functions.php (para marcar enlaces externos y añadir texto accesible) y la potencia de CSS mask, puedes mostrar un icono automático y coloreable junto a los enlaces externos sin añadir elementos extra visibles ni sobrecargar recursos. El resultado es ligero, accesible y fácil de mantener.



Leave a Reply

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