Introducción

Que levante la mano el primero que se haya topado con que en esta vida está todo inventado. Eso es lo que yo pensaba tras varias semanas utilizando Tailwind CSS, una biblioteca de estilos muy madura y estandarizada en el mundo del desarrollo de Software moderno. Sin embargo, resultó no ser así, y algo que era tan básico para mí, resultó no estar implementado.

El reto

Durante el desarrollo de mi Blog, en el que trabajo con la ya mencionada biblioteca, me surgió la necesidad de aprovechar el color de texto de un elemento como color de fondo del mismo, pero con una opacidad inferior. Si aplicara ambos colores con la misma opacidad, el texto sería ilegible.

Evidentemente, se trataba de aprovechar dinámicamente el valor actual de la propiedad text-color del elemento para no tener que especificarlo.

La idea que tenía en mente era la siguiente:

Este contenedor tiene un elemento span en su interior.

Como se puede apreciar, el elemento span, comparte el color del texto para su fondo y borde. El color del texto se define en su contenedor, por lo que en el span nunca se especifica un código de color determinado.

Bien, pues puestos en materia, lo primero que pensé, cuando me surió la necesidad, fue en emplear el currentColor como color de las clases bg- y border-de Tailwind CSS. Y eso es posible. Sin embargo, si no especificamos una opacidad, obtendríamos lo siguiente:

Este contenedor tiene un elemento span en su interior.
<!-- Ejemplo sin especificar la opacidad -->

<div
  class="inline-block rounded-md border border-current p-2 text-lime-800 dark:text-lime-500"
>
  Este contenedor tiene un elemento
  <span
    class="rounded-md border border-current bg-current px-1 font-mono text-sm"
    >span</span
  >
  en su interior.
</div>

Por lo tanto, pensé en que si quisiera aplicarle una transparencia a un fondo y borde de un color específico, tendría que emplear las clases bgo-opacity-15 y border-opacity-60 en mi código.

Así que llevado al terreno del currentColor, ¿qué tal haciendo esta combinación?

  • bg-current bg-opacity-15 border-current border-opacity-60

Pues bien, eso no funcionó:

Este contenedor tiene un elemento span en su interior.
<!-- Ejemplo especificando la opacidad con bg-opacity y border-opacity -->

<div
  class="inline-block rounded-md border border-current p-2 text-lime-800 dark:text-lime-500"
>
  Este contenedor tiene un elemento
  <span
    class="rounded-md border border-current border-opacity-60 bg-current bg-opacity-15 px-1 font-mono text-sm"
    >span</span
  >
  en su interior.
</div>

La solución

Tras investigar varias decenas de minutos, otras más decenas de pruebas y combinaciones, y con unas cuantas decenas de miles de neuronas menos, opté por crear yo mismo las clases para aplicar una transparencia al color de fondo y de borde cuando este sea el currentColor.

¿Cómo? Empecemos por el archivo de configuración de Tailwind CSS. Aquí tenemos que extender las clases existentes de backgroundColor y borderColor.

Para lograr el efecto deseado con distintos niveles de transparencia, emplearemos color-mix(), una función de CSS que toma dos valores de color y los mezcla para devolver uno solo como resultado, en función del porcentaje que se otorga a cada color. Esta función la emplearemos para mezclar el currentColor con el color transparent, e iremos jugando con el porcentaje de currentColor para que sea más o menos transparente.

Veamos cómo quedaría esto en el archivo tailwind.config.mjs:

// tailwind.config.js

module.exports = {
  theme: {
    extend: {
      backgroundColor: {
        'current/0': 'color-mix(in srgb, currentColor 0%, transparent)',
        'current/5': 'color-mix(in srgb, currentColor 5%, transparent)',
        'current/10': 'color-mix(in srgb, currentColor 10%, transparent)',
        'current/15': 'color-mix(in srgb, currentColor 15%, transparent)',
        'current/20': 'color-mix(in srgb, currentColor 20%, transparent)',
        'current/25': 'color-mix(in srgb, currentColor 25%, transparent)',
        'current/30': 'color-mix(in srgb, currentColor 30%, transparent)',
        'current/35': 'color-mix(in srgb, currentColor 35%, transparent)',
        'current/40': 'color-mix(in srgb, currentColor 40%, transparent)',
        'current/45': 'color-mix(in srgb, currentColor 45%, transparent)',
        'current/50': 'color-mix(in srgb, currentColor 50%, transparent)',
        'current/55': 'color-mix(in srgb, currentColor 55%, transparent)',
        'current/60': 'color-mix(in srgb, currentColor 60%, transparent)',
        'current/65': 'color-mix(in srgb, currentColor 65%, transparent)',
        'current/70': 'color-mix(in srgb, currentColor 70%, transparent)',
        'current/75': 'color-mix(in srgb, currentColor 75%, transparent)',
        'current/80': 'color-mix(in srgb, currentColor 80%, transparent)',
        'current/85': 'color-mix(in srgb, currentColor 85%, transparent)',
        'current/90': 'color-mix(in srgb, currentColor 90%, transparent)',
        'current/95': 'color-mix(in srgb, currentColor 95%, transparent)',
        'current/100': 'color-mix(in srgb, currentColor 100%, transparent)',
      },
      borderColor: {
        'current/0': 'color-mix(in srgb, currentColor 0%, transparent)',
        'current/5': 'color-mix(in srgb, currentColor 5%, transparent)',
        'current/10': 'color-mix(in srgb, currentColor 10%, transparent)',
        'current/15': 'color-mix(in srgb, currentColor 15%, transparent)',
        'current/20': 'color-mix(in srgb, currentColor 20%, transparent)',
        'current/25': 'color-mix(in srgb, currentColor 25%, transparent)',
        'current/30': 'color-mix(in srgb, currentColor 30%, transparent)',
        'current/35': 'color-mix(in srgb, currentColor 35%, transparent)',
        'current/40': 'color-mix(in srgb, currentColor 40%, transparent)',
        'current/45': 'color-mix(in srgb, currentColor 45%, transparent)',
        'current/50': 'color-mix(in srgb, currentColor 50%, transparent)',
        'current/55': 'color-mix(in srgb, currentColor 55%, transparent)',
        'current/60': 'color-mix(in srgb, currentColor 60%, transparent)',
        'current/65': 'color-mix(in srgb, currentColor 65%, transparent)',
        'current/70': 'color-mix(in srgb, currentColor 70%, transparent)',
        'current/75': 'color-mix(in srgb, currentColor 75%, transparent)',
        'current/80': 'color-mix(in srgb, currentColor 80%, transparent)',
        'current/85': 'color-mix(in srgb, currentColor 85%, transparent)',
        'current/90': 'color-mix(in srgb, currentColor 90%, transparent)',
        'current/95': 'color-mix(in srgb, currentColor 95%, transparent)',
        'current/100': 'color-mix(in srgb, currentColor 100%, transparent)',
      },
    },
  },
  plugins: [],
}
ℹ️

En ambos arreglos empleo el sufijo current/{valor} para darle un sentido a la ya existente clase de Tailwind CSS text-{color}-500/{valor}. No obstante, esto va a gustos, y puedes cambiarlo por current-{valor}, o por lo que prefieras.

Ahora, en el archivo global.css podrías emplear las clases, siempre y cuando hagas las importaciones pertinentes:

/* global.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

El resultado

Veamos varios ejemplos de cómo afectarían las clases que acabamos de crear:

  • bg-current/0: Esta clase tomaría el color del texto del elemento actual para el fondo, pero al tener una opacidad de 0, sería lo mismo que darle un fondo transparente.
  • bg-current/50: Esta clase tomaría el color del texto del elemento actual para el fondo, pero con una opacidad del 50%, permitiendo que el texto sea legible.
  • bg-current/100: Esta clase tomaría el color del texto del elemento actual para el fondo, pero al tener una opacidad del 100%, impediría leer el texto.
  • boder-current/0: Esta clase tomaría el color del texto del elemento actual para el borde, pero al tener una opacidad de 0, sería lo mismo que darle un borde transparente.
  • boder-current/50: Esta clase tomaría el color del texto del elemento actual para el borde y le daría una opacidad del 50%.
  • boder-current/100: Esta clase tomaría el color del texto del elemento actual para el borde y le daría una opacidad del 100%.

Así pues, veamos cómo quedarían las clases del ejemplo que vimos al principio:

Este contenedor tiene un elemento span en su interior.
<!-- Ejemplo empleando nuestras nuevas clases 🔥 -->

<div
  class="inline-block rounded-md border border-current p-2 text-lime-800 dark:text-lime-500"
>
  Este contenedor tiene un elemento
  <span
    class="rounded-md border border-current/60 bg-current/15 px-1 font-mono text-sm"
    >span</span
  >
  en su interior.
</div>

Como puedes apreciar, conseguimos el efecto deseado gracias a las clases personalizadas border-current/60 y bg-current/15.

🚀 ¡Espero que te sea útil!