Logo Gerardo Perrucci - Full Stack Developer

CSS `mask-image`: Guía completa de uso y buenas prácticas

Introducción a mask-image

mask-image

El masking en CSS permite a los desarrolladores ocultar partes de un elemento sin eliminarlas permanentemente (CSS Masking). La propiedad mask-image en CSS permite esto al permitirte usar una imagen (incluyendo SVG o gradientes CSS) como una capa de máscara sobre un elemento (Apply effects to images with the CSS mask-image property).

En la práctica, la transparencia de la máscara controla qué partes del elemento objetivo son visibles: las áreas totalmente transparentes de la máscara ocultan esas partes del elemento, mientras que las áreas opacas muestran el contenido debajo (mask-image - CSS: Cascading Style Sheets). Esta técnica es muy potente para crear efectos visuales creativos: puedes lograr formas complejas, desvanecimientos y recortes sin necesidad de editar la imagen original en un editor externo (Apply effects to images with the CSS mask-image property).

Uno de los principales beneficios de mask-image es que se aplica completamente con CSS, lo que significa que se puede actualizar o animar fácilmente y combinar con otros estilos. La sintaxis y las propiedades complementarias de las máscaras CSS son muy similares a las de los backgrounds de CSS (por ejemplo, puedes usar mask-repeat, mask-position y mask-size de forma análoga a las propiedades de fondo) (CSS Masking). Esto facilita que los desarrolladores familiarizados con imágenes de fondo comiencen a trabajar con máscaras. Por defecto, la máscara utiliza el canal alfa (opacidad) de la imagen para determinar la visibilidad del elemento, aunque este comportamiento puede ajustarse (por ejemplo, usando máscaras de luminancia) con propiedades adicionales si es necesario.

En resumen, mask-image ofrece una forma de aplicar una máscara alfa a cualquier elemento HTML, controlando su visibilidad de manera sofisticada. Esto abre la puerta a diseñar formas ornamentales, transiciones suaves y efectos en capas directamente desde el código. Desde finales de 2023, el masking en CSS cuenta con un amplio soporte en los navegadores modernos (mask-image - CSS: Cascading Style Sheets), convirtiendo a mask-image en una herramienta viable para producción que mejora el diseño visual sin ensuciar el HTML.

Comparaciones con Propiedades Similares

CSS ofrece múltiples técnicas para dar forma o combinar elementos. Es importante entender cómo mask-image se diferencia de otras propiedades relacionadas como clip-path y background-blend-mode, para que puedas elegir la herramienta adecuada para cada caso de uso.

mask-image vs clip-path

clip-path también oculta partes de un elemento, pero funciona de manera muy distinta al masking. Cuando recortas un elemento usando clip-path, cualquier parte del elemento que quede fuera de la forma especificada se vuelve completamente invisible (no se renderiza en absoluto) y con bordes duros (Apply effects to images with the CSS mask-image property). El recorte se define mediante formas vectoriales (círculos, polígonos, etc.), por lo que clip-path es ideal para recortes geométricos simples. Sin embargo, no admite transparencia parcial ni transiciones suaves: la región recortada está 100% visible o 100% ausente.

mask-image, en cambio, utiliza una imagen o gradiente como superposición para determinar la visibilidad. Esto significa que puede crear bordes difuminados, gradientes suaves y patrones de transparencia complejos, no solo formas básicas. La diferencia principal es que mask-image funciona con imágenes y gradientes (y por lo tanto puede aprovechar los niveles de opacidad), mientras que clip-path trabaja con rutas vectoriales y produce una máscara binaria (CSS Masking). Por ejemplo, si quieres desvanecer gradualmente una imagen en los bordes o tener una forma compleja con un borde desenfocado, mask-image es la elección adecuada. Con clip-path solamente, ese tipo de efectos sería imposible porque las áreas recortadas no permiten opacidad parcial.

En la práctica, podrías usar clip-path cuando necesitas crear una forma no rectangular de manera sencilla (por ejemplo, convertir una imagen en un círculo o un polígono) y no necesitas ningún tipo de gradiente de transparencia. Es una solución directa y con buen soporte para formas. Usa mask-image cuando necesites más control creativo: por ejemplo, aplicar una textura de máscara detallada, un desvanecimiento por gradiente, o cualquier escenario donde partes del elemento deban ser semitransparentes en lugar de desaparecer por completo. Vale la pena mencionar que incluso puedes combinar masking y clipping para escenarios avanzados, pero generalmente estas propiedades cubren necesidades distintas. Como regla general, usa clip-path para recortes geométricos simples, y mask-image para máscaras elaboradas y efectos de transparencia.

mask-image vs background-blend-mode

background-blend-mode es una propiedad que afecta cómo se combinan las capas de fondo de un elemento entre sí y con el color de fondo del propio elemento (background-blend-mode). Esto es fundamentalmente distinto de lo que hace mask-image. background-blend-mode no oculta ninguna parte del elemento; en su lugar, mezcla los colores de los fondos (por ejemplo, si tienes múltiples imágenes de fondo apiladas, puedes combinarlas con modos como multiply, screen, overlay, etc.). Es similar a la mezcla de capas en Photoshop, aplicada a fondos en CSS.

En cambio, mask-image controla la transparencia del contenido del elemento superponiendo una imagen como máscara. No hay mezcla de colores involucrada: la máscara simplemente indica dónde el elemento es opaco, parcialmente transparente o completamente transparente. Por ejemplo, si quisieras lograr un efecto duotone o una superposición de color sobre una imagen, podrías usar modos de mezcla; pero si quisieras dar forma a esa imagen como una estrella o hacer que se desvanezca, usarías masking.

Para ilustrarlo, imagina una imagen que quieres que parezca pintada sobre un fondo texturizado. Usando background-blend-mode: multiply podrías hacer que los colores de la imagen se mezclen con un patrón de textura detrás. Sin embargo, la forma de la imagen seguiría siendo un rectángulo. Si en su lugar usas una imagen de textura como mask-image, podrías hacer que la propia imagen adopte la forma de esa textura (partes de la imagen serían transparentes según la máscara). En resumen, usa background-blend-mode para combinar colores/capas y lograr efectos de estilo con el color, y usa mask-image cuando necesites definir un patrón o forma de transparencia personalizada para un elemento. Incluso pueden usarse juntos (por ejemplo, un elemento puede tener capas de fondo mezcladas y además una máscara aplicada), pero resuelven problemas distintos y no son intercambiables.

Ejemplos de implementación

Nada mejor que ejemplos reales para demostrar cómo funciona mask-image. En esta sección exploraremos algunos escenarios: cómo aplicar máscaras con CSS puro de distintas maneras, y luego cómo usar JavaScript/React para actualizar las máscaras dinámicamente.

Ejemplos de máscaras con CSS puro

Empecemos con algunos ejemplos de CSS puro que muestran distintas formas de usar mask-image. Estos ejemplos asumen que tienes algún elemento (imagen, texto o un div con fondo) que deseas enmascarar.

Ejemplo 1: Máscara con desvanecimiento por gradiente (Efecto de desvanecimiento de imagen) – Supongamos que tienes una imagen y quieres que se desvanezca gradualmente a transparente en la parte inferior (un efecto común en interfaces con contenedores con scroll o simplemente por estilo). Puedes lograr esto con un gradiente CSS como máscara:

<div class="fade-image">
  <!-- This div uses a background image to demonstrate the mask effect -->
</div>
.fade-image {
  width: 300px;
  height: 200px;
  background: url('photo.jpg') center/cover no-repeat;
  /* Apply a top-to-bottom gradient mask: fully opaque at top, transparent at bottom */
  mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
  mask-size: 100% 100%;
  mask-repeat: no-repeat;
  /* For broader support (Safari), include the WebKit-prefixed version: */
  -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
  -webkit-mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
}

En este código, mask-image: linear-gradient(to bottom, black 60%, transparent 100%) crea un gradiente que es negro sólido en el 60% superior del elemento y se desvanece hasta volverse completamente transparente en la parte inferior. Como por defecto la máscara usa el canal alfa (y el negro es completamente opaco), la parte superior del elemento permanece visible, mientras que la parte inferior se vuelve gradualmente transparente. El resultado es una imagen que se desvanece suavemente hacia abajo. Usamos mask-repeat: no-repeat y mask-size: 100% 100% para asegurarnos de que el gradiente cubra todo el elemento una sola vez (al igual que se haría con una imagen de fondo para evitar que se repita). La sintaxis de estas propiedades de máscara es análoga a sus equivalentes de fondo (por ejemplo, mask-size: cover funcionaría como background-size: cover (Apply effects to images with the CSS mask-image property  |  Articles  |  web.dev)). Las líneas con prefijo -webkit-mask-* están incluidas para Safari y navegadores WebKit antiguos que requieren el prefijo.

Ejemplo 2: Máscara con imagen (Dar forma a un elemento con una imagen como máscara) – Ahora vamos a usar una imagen real como máscara. Imagina que tienes una forma decorativa (por ejemplo, una silueta de estrella) como PNG o SVG, y quieres que un elemento (por ejemplo, una foto o incluso un bloque de contenido) aparezca solo dentro de esa forma de estrella. Así es como podrías hacerlo:

<div class="star-mask">
  <!-- This div could contain content or have a background image that will be masked -->
</div>
.star-mask {
  width: 300px;
  height: 300px;
  background: url('picture.jpg') center/cover no-repeat;
  mask-image: url('star-shape.png');
  mask-mode: alpha; /* ensure we use the alpha channel of the PNG */
  mask-repeat: no-repeat;
  mask-position: center;
  mask-size: contain;
  -webkit-mask-image: url('star-shape.png'); /* Safari prefix */
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
}

Aquí, mask-image: url("star-shape.png") utiliza un archivo de imagen externo (que debe tener transparencia) como máscara. Típicamente, una imagen de máscara como esta sería una forma negra sobre un fondo transparente (o cualquier forma completamente opaca — el color no importa, solo el canal alfa cuando se usa mask-mode: alpha). El CSS anterior restringirá la visibilidad del fondo de .star-mask a la silueta de la estrella. Usamos mask-size: contain para que la imagen de máscara se escale y se ajuste completamente dentro del área del elemento (manteniendo su proporción), y mask-position: center para alinearla en el centro. El resultado es que la foto de fondo solo se mostrará donde la forma de estrella tenga píxeles opacos; todo lo que esté fuera de esa forma será transparente, recortando efectivamente la foto con forma de estrella. Al igual que con los fondos, puedes ajustar mask-position y mask-size para lograr la colocación y escala correctas de la máscara (de hecho, la sintaxis de posicionamiento de la máscara es idéntica a la de los fondos (CSS Masking)). Nuevamente, incluimos versiones con prefijo WebKit para compatibilidad.

Ejemplo 3: Combinando múltiples máscaras (Avanzado) – La especificación de CSS Masking permite múltiples capas de máscara, de forma similar a los múltiples fondos. Aunque es menos común, a veces podrías superponer máscaras para lograr efectos complejos. Por ejemplo, podrías usar dos máscaras: una imagen raster y un gradiente. El navegador las compondrá (por defecto, intersectando sus canales alfa). En CSS, se vería así:

.multi-mask-example {
  /* ... element styles ... */
  mask-image: url('texture-mask.png'), radial-gradient(circle, transparent 30%, black 100%);
  mask-composite: add; /* how multiple masks combine; default is add which essentially multiplies alpha */
  mask-repeat: no-repeat, no-repeat;
  mask-position: center, center;
  mask-size:
    cover,
    100% 100%;
}

En este fragmento, el elemento está enmascarado por una textura y un gradiente radial (quizás creando un efecto viñeta donde los bordes se desvanecen y además se superpone una textura). Los detalles de mask-composite están fuera del alcance de esta explicación, pero vale la pena señalar que las máscaras múltiples pueden lograr efectos visuales muy complejos. En la práctica, lo más común es usar una sola máscara a la vez, pero es útil saber que esta posibilidad de capas está disponible para casos avanzados.

Actualización dinámica de máscaras con JavaScript y React

Las máscaras se pueden manipular dinámicamente como cualquier otra propiedad CSS. Esto significa que puedes usar JavaScript (o código en un framework) para cambiar mask-image sobre la marcha — para efectos interactivos, cambio de temas o animaciones.

Usando JavaScript puro (Vanilla): Puedes alternar o animar una máscara cambiando el estilo o clase del elemento. Por ejemplo, imagina una foto de perfil que, al hacer hover, cambia de una máscara circular a una en forma de estrella. Podrías tener dos clases CSS definidas (una con una máscara de gradiente circular y otra con una máscara SVG de estrella). En JavaScript, podrías escuchar eventos de hover o click y cambiar la clase:

.image-container {
  position: relative;
  border: 1px gray solid;
}
.image-container img {
  display: block;
  /* Apply a top-to-bottom gradient mask: fully opaque at top, transparent at bottom */
  mask-image: linear-gradient(to bottom, rgb(161, 161, 161) 0%, transparent 100%);
  mask-size: 100% 100%;
  mask-repeat: no-repeat;
}

.image-container img.follow-mask {
  display: block;
  width: 100%;
  height: auto;
  mask-image: url('./pawn.webp'), radial-gradient(circle, transparent 10%, black 100%);
  mask-composite: add;
  mask-size: 300px 300px;
  mask-repeat: no-repeat;
}
<div class="image-container">
  <img src="./chessboard.webp" width="100%" />
</div>
document.addEventListener('DOMContentLoaded', () => {
  const image = document.querySelector('.image-container img');

  image.addEventListener('mouseenter', e => {
    image.classList.add('follow-mask');
  });

  image.addEventListener('mousemove', e => {
    const rect = image.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    image.style.maskPosition = `${x - 150}px ${y - 150}px`;
  });

  image.addEventListener('mouseleave', () => {
    console.log('here');
    image.classList.remove('follow-mask');
    image.style.maskPosition = '0px 0px';
  });
});

En este código hipotético, cuando el usuario pasa el mouse sobre el elemento img, se añade una clase que cambia la máscara a una forma de peón. Al quitar el mouse, se elimina esa clase, volviendo a la máscara original. La transición CSS en mask-image proporciona una interpolación suave (nota: no todos los navegadores pueden interpolar máscaras complejas de manera fluida, pero las transiciones simples con gradientes suelen funcionar).

También puedes establecer directamente el estilo con JavaScript. Por ejemplo:

element.style.maskImage = 'url("mask2.png")';
element.style.webkitMaskImage = 'url("mask2.png")';

Esto cambiaría inmediatamente la máscara en ese elemento (aquí asignamos tanto la propiedad estándar como la prefijada con -webkit- para compatibilidad). Este enfoque es útil si el valor de la máscara es dinámico o calculado mediante script.

Usando React (u otros frameworks): En React, puedes controlar mask-image mediante state o props, como cualquier otro estilo. Aquí tienes un ejemplo simple de un componente de React que permite al usuario alternar entre dos efectos de máscara sobre una imagen: React component that lets a user toggle between two masking effects on an image:

import React, { useState } from 'react';
import './styles.css';

function App() {
  const [maskShape, setMaskShape] = useState('circle');

  const handleShapeChange = shape => {
    setMaskShape(shape);
  };

  return (
    <div className="App">
      <div className="button-container">
        <button onClick={()=> handleShapeChange('circle')}>Circle</button>
        <button onClick={()=> handleShapeChange('rectangle')}>Rectangle</button>
        <button onClick={()=> handleShapeChange('triangle')}>Triangle</button>
      </div>
      <div className="image-container">
        <svg width="0" height="0">
          <defs>
            <mask id="circle-mask" maskUnits="objectBoundingBox">
              <circle cx="400" cy="50" ="120" fill="#FFFFFF" />
              <circle cx="100" cy="50" ="120" fill="#FFFFFF" />
            </mask>
            <mask id="rectangle-mask" maskUnits="objectBoundingBox">
              <rect width="130" height="130" fill="#FFFFFF" />
              <rect width="130" height="130" ="120" ="120" fill="#FFFFFF" />
              <rect width="130" height="130" ="0" ="220" fill="#FFFFFF" />
              <rect width="130" height="130" ="120" ="320" fill="#FFFFFF" />
            </mask>
            <mask id="triangle-mask" maskUnits="objectBoundingBox">
              <polygon points="200,0 0,85 200,205" fill="#FFFFFF" />
              <polygon points="400,0 200,85 400,205" fill="#FFFFFF" />
            </mask>
          </defs>
        </svg>
        <img src="chessboard.webp" alt="Masked" className={`masked-image ${maskShape}`} />
      </div>
    </div>
  );
}

export default App;
.App {
  text-align: center;
}

.button-container {
  margin: 20px;
}

.image-container {
  display: inline-block;
  position: relative;
}

.masked-image {
  width: 500px;
  transition: mask-image 0.5s ease-in-out;
}

.masked-image.circle {
  -webkit-mask-image: url(#circle-mask);
  mask-image: url(#circle-mask);
}

.masked-image.rectangle {
  -webkit-mask-image: url(#rectangle-mask);
  mask-image: url(#rectangle-mask);
}

.masked-image.triangle {
  -webkit-mask-image: url(#triangle-mask);
  mask-image: url(#triangle-mask);
}

En este componente de React, mantenemos un estado llamado mask que determina qué estilo de máscara aplicar. Al hacer clic en el botón, se alterna el estado de la máscara entre 'circle', 'rectangle' y 'triangle', lo que actualiza el estilo de la imagen en consecuencia (gracias a que React vuelve a renderizar con el nuevo estado). Esto hace que el elemento cambie su forma de máscara al hacer clic. Puedes extender esta idea a muchos otros escenarios interactivos: ajustar una máscara según la posición de scroll, usar un slider para cambiar la intensidad de un gradiente, etc.

Nota sobre animaciones: Es posible animar propiedades de máscara usando animaciones o transiciones CSS (como se mostró en la transición con hover). Sin embargo, no todos los aspectos son fáciles de animar – por ejemplo, animar el cambio entre dos imágenes SVG como máscara podría resultar en un cambio abrupto. Los gradientes suelen poder animarse ajustando sus paradas o coordenadas. Si necesitas un control más preciso en la animación de máscaras, considera técnicas como animar un elemento <mask> en SVG o usar mask-position para deslizar una máscara sobre un elemento. Ten en cuenta el rendimiento (tema que trataremos más adelante) al hacer animaciones: mover o cambiar una máscara frecuentemente puede ser más costoso que transformaciones CSS estándar o cambios de opacidad.

Casos de uso

Ahora que vimos cómo usar mask-image, ¿cuándo deberías usarlo? A continuación cubrimos escenarios donde mask-image brilla, y algunas buenas prácticas a tener en cuenta.

Cuándo y por qué usar mask-image

Formas no rectangulares o complejas: Siempre que quieras que un elemento adopte una forma que no es fácil de lograr solo con CSS, una máscara puede ayudarte. Por ejemplo, convertir una imagen en una estrella, un corazón, letras, o incluso una silueta arbitraria. Aunque algunas formas simples (círculo, elipse, polígono) pueden lograrse con clip-path o border-radius, mask-image te permite usar cualquier imagen como plantilla, lo que significa que tus formas pueden incluir bordes suaves, huecos o contornos detallados. Los diseñadores suelen crear máscaras PNG/SVG para marcos de imagen únicos, avatares personalizados o transiciones decorativas entre secciones. Con mask-image, estos diseños pueden implementarse fácilmente en el navegador. Incluso puedes aplicar máscaras a texto o bloques enteros de contenido para que aparezcan dentro de una forma (por ejemplo, mostrar texto solo donde una textura tipo grunge tenga huecos, creando un efecto de texto desgastado).

Desvanecimientos graduales y efectos de transparencia: Si necesitas que parte de un elemento se desvanezca suavemente o sea parcialmente transparente, el masking es la solución ideal. Un caso clásico es desvanecer el contenido inferior de un contenedor con scroll (para indicar que hay más contenido), o desvanecer los bordes de una imagen tipo slideshow en el fondo. Simplemente aplicas una máscara con gradiente como hicimos en el ejemplo, en lugar de depender de un editor de imágenes para aplicar el efecto. Esto hace que el efecto sea flexible (puedes ajustarlo con CSS o activarlo/desactivarlo con una clase) y responsivo (la máscara escalará con el elemento si está configurada apropiadamente). Es mucho más adaptable que una imagen estática con un fade incorporado. En general, cualquier efecto donde quieras opacidad variable en un elemento (no solo una opacidad global) es candidato para mask-image.

Estilización de texto e íconos: Las máscaras no son solo para imágenes o divs; también puedes aplicarlas a elementos de texto (como span o h1). Esto permite efectos tipográficos muy interesantes – por ejemplo, hacer que el texto aparezca con un desvanecimiento por gradiente o con un estilo recortado donde una textura se muestra a través de las letras. Un enfoque común para estilizar texto es usar background-clip: text con una imagen de fondo, pero mask-image en un elemento de texto puede lograr resultados diferentes (como hacer visibles solo ciertas partes de las letras). De forma similar, en íconos (que podrían ser fuentes o SVG), puedes aplicar una máscara para crear un efecto de plantilla. Un ejemplo práctico podría ser un ícono que sirve como máscara para una galería de fotos (mostrando la foto a través de la forma del ícono). Las posibilidades son bastante amplias cuando se trata de estilos visuales.

Revelaciones interactivas y efectos hover: Dado que puedes animar y cambiar máscaras, mask-image puede usarse para efectos interactivos como revelaciones al pasar el mouse o transiciones. Por ejemplo, en un portfolio, podrías hacer hover sobre una miniatura y hacer que cambie de rectángulo a una forma compleja mediante una máscara animada, captando la atención de forma única. Otro ejemplo es hacer clic en un botón que activa una máscara superpuesta que se anima y revela contenido debajo con un efecto tipo barrido. Este tipo de efectos pueden usar animaciones CSS en propiedades de máscara o actualizaciones mediante JavaScript, como se mostró. Permiten mucha más creatividad que simples fades o slides—imagina un efecto de “periódico quemándose” logrado animando una máscara con bordes quemados, por ejemplo.

En resumen, usa mask-image cuando necesites control detallado sobre la visibilidad de un elemento que va más allá de la opacidad uniforme o el recorte geométrico básico. Destaca al crear visuales llamativos como recortes transparentes (por ejemplo, un botón con texto recortado que deja ver lo que hay detrás) (Masking images in CSS with the mask-image property - LogRocket Blog), filtros u overlays en imágenes mediante capas de máscaras (por ejemplo, usando una máscara en escala de grises para desaturar selectivamente partes de una imagen) (Masking images in CSS with the mask-image property - LogRocket Blog), y en general siempre que antes hubieras recurrido a Photoshop para enmascarar algo — ahora muchas veces puedes hacerlo directamente con CSS.

Buenas prácticas (Rendimiento y Accesibilidad)

Aunque mask-image es una herramienta poderosa, también es una funcionalidad bastante avanzada a nivel del navegador. Aquí tienes algunas buenas prácticas para usarla de manera eficiente y accesible:

  • Mantén las máscaras simples siempre que sea posible: El navegador debe calcular el efecto de la máscara píxel por píxel. Las máscaras simples (como gradientes básicos o imágenes pequeñas) suelen funcionar bien. Pero las máscaras muy grandes o complejas (especialmente si las animas) pueden saturar la canalización de renderizado del navegador. Por ejemplo, un desarrollador reportó que animar una máscara de puntos (usando un repeating-radial-gradient) causó una gran caída en el rendimiento en Firefox (The Two Lines of CSS That Tanked Performance (120fps to 40fps)). Si notas problemas de rendimiento, considera simplificar la máscara (por ejemplo, usar una imagen de menor resolución o animar con menos frecuencia) o activar el efecto solo cuando sea necesario. Además, es posible que las máscaras en CSS estén aceleradas por hardware en algunos navegadores, pero no en otros – prueba en todos los navegadores que quieras soportar.

  • Evita repintados constantes si no son necesarios: Si animas una máscara cambiando mask-position o alternando imágenes rápidamente, estarás provocando repintados del contenido. Siempre que sea posible, usa transiciones CSS y deja que el navegador optimice. Si usas JavaScript, limita los cambios rápidos (por ejemplo, usando requestAnimationFrame para actualizaciones suaves). Y si un efecto es solo decorativo, puedes desactivarlo en dispositivos de bajo rendimiento o navegadores con problemas (como en el ejemplo donde se desactiva la animación en Firefox por cuestiones de rendimiento (The Two Lines of CSS That Tanked Performance (120fps to 40fps))). Siempre considera usar la media query prefers-reduced-motion para desactivar animaciones de máscaras elaboradas para usuarios que prefieren menos movimiento — esto no solo ayuda a esos usuarios, sino que también puede mejorar el rendimiento en esos casos (como se muestra en nuestro ejemplo de código donde se desactivó la animación en tales escenarios).

  • Proporciona degradación elegante o fallbacks: No todos los navegadores soportan mask-image (ver compatibilidad más abajo). Asegúrate de que si la máscara no se aplica, el contenido siga siendo visible y presentable. Normalmente, si la máscara no es soportada, el elemento se mostrará de forma normal (sin máscara), lo cual suele estar bien. Pero verifica que la ausencia de máscara no arruine el diseño. Por ejemplo, si querías mostrar texto blanco sobre un fondo oscuro a través de una máscara recortada, y la máscara falla, podrías terminar con texto blanco sobre fondo blanco. En estos casos, usa feature queries (por ejemplo, @supports (mask-image: url()) { ... }) para aplicar estilos alternativos o asegurar que el estilo base funcione sin máscara. Incluir el prefijo -webkit-mask-image es esencial para Safari y versiones antiguas de Chrome — ya vimos en los ejemplos cómo incluirlos. Para una cobertura más amplia, también podrías incluir -moz-mask-image y -o-mask-image, incluso si no son estándar, como sugiere alguna documentación (Masking images in CSS with the mask-image property - LogRocket Blog) (Firefox usa la propiedad sin prefijo en sus versiones modernas, y Opera históricamente sigue los prefijos WebKit).

  • Accesibilidad – Considera el impacto de ocultar contenido: Las máscaras son puramente visuales y no eliminan el contenido del DOM ni de la tecnología asistiva. De hecho, las partes ocultas del elemento aún existen en términos de layout y detección de eventos – la máscara no cambia la geometría real del elemento (CSS Masking Module Level 1). Esto tiene varias implicaciones:

    • Para usuarios de lectores de pantalla, si enmascaras parte del contenido (por ejemplo, la mitad de una imagen), el lector de pantalla seguirá leyendo el texto alternativo completo. Normalmente esto está bien (reciben la descripción, que es lo deseado). Pero ten cuidado si estabas usando una máscara para ocultar algo como texto visible; ese texto aún podría ser leído. Si realmente quieres que cierto contenido no sea accesible, no confíes en una máscara: utiliza técnicas adecuadas como aria-hidden="true" o directamente no lo renderices.

    • Para interacciones con el puntero, un elemento enmascarado sigue interceptando clics en toda el área de su caja, incluso si esa zona es completamente transparente debido a la máscara. Por ejemplo, si tienes un botón con forma de estrella mediante máscara, las esquinas del botón (fuera de la estrella pero dentro del bounding box) son transparentes pero seguirán bloqueando clics hacia elementos detrás del botón. Probablemente los usuarios no intenten hacer clic a través de un botón visible, pero si tienes elementos superpuestos, recuerda que las máscaras no crean agujeros reales para el mouse. Si es necesario, ajusta pointer-events o el layout. Un enfoque común para formas interactivas irregulares es usar un <svg> con un <mask> o <clipPath> real para precisión de puntero, o simplemente aceptar el área de clic rectangular.

    • Asegúrate de que el propósito de la máscara sea decorativo o de mejora visual, y no transmita información que algunos usuarios puedan perderse. Por ejemplo, si el hecho de que una imagen tenga un borde como de papel rasgado es importante para entender el contenido, eso podría no ser evidente para usuarios no visuales. Por lo general, las máscaras son estéticas, así que no suele ser un problema, pero vale la pena tenerlo en cuenta.

  • Optimización de imágenes de máscara: Si usas imágenes externas (PNG/SVG) como máscaras, optimiza su tamaño y complejidad. Para PNG, usa PNG con canal alfa de 8 bits si es posible (a menos que necesites color completo en la máscara, lo cual es raro si solo usas el canal alfa). Máscaras grandes (por ejemplo, un PNG enorme) pueden ralentizar el renderizado; si la imagen de máscara es mucho más grande de lo necesario, considera reducir su escala. Las máscaras SVG pueden ser más eficientes para diseños escalables y suelen tener menor tamaño de archivo para formas geométricas. También pueden incrustarse en el HTML y referenciarse mediante mask-image: url(#maskID) en la misma página (aunque el soporte entre navegadores puede variar). Prueba diferentes formatos: una máscara SVG puede renderizar más rápido que una PNG en algunos casos al ser vectorial. Además, recuerda el caching: las imágenes de máscara externas se cargan como cualquier otro recurso. Si reutilizas la misma máscara en varios elementos, eso es bueno para el rendimiento (una imagen, múltiples usos). Pero si tienes muchas máscaras diferentes y pesadas, eso implica mayor carga de red y uso de memoria.

En resumen, usa mask-image con criterio: es ideal para embellecimiento, no como base estructural del diseño. Asegúrate de que tu interfaz siga siendo funcional y comprensible sin las máscaras (para quienes no las pueden ver o si no se cargan), y luego aprovecha el potencial visual cuando estén disponibles. Con un uso prudente, puedes lograr efectos llamativos sin inconvenientes significativos.

Compatibilidad entre navegadores

La propiedad mask-image fue considerada durante bastante tiempo como una parte experimental de CSS, pero ahora forma parte del estándar oficial CSS Masking Module Level 1 y está soportada por todos los navegadores modernos principales (con algunas advertencias en versiones más antiguas). A finales de 2023, mask-image sin prefijo ya es compatible con las versiones actuales de Chrome, Edge, Firefox y Safari (mask-image - CSS: Cascading Style Sheets | MDN).

En la práctica, esto significa que si escribes mask-image en tu CSS, funcionará en los navegadores actualizados tanto en escritorio como en móviles. Sin embargo, para mayor compatibilidad con versiones ligeramente más antiguas, deberías incluir también la versión con prefijo WebKit. Muchas de las funcionalidades de mask-image estaban disponibles únicamente mediante -webkit-mask-image en Safari y versiones antiguas de Chrome o navegadores Android.

Resumen rápido de compatibilidad:

  • Chrome – Soporta completamente mask-image (sin prefijo) en versiones recientes. Versiones anteriores (de Chrome 4 hasta aprox. la 68) solo soportaban -webkit-mask-image para ciertas funcionalidades (especialmente máscaras con gradientes) (Mask-image - CSS - W3cubDocs). Desde Chrome 79+, el soporte sin prefijo es sólido.
  • Firefox – Soporta mask-image sin prefijo desde Firefox 53 (la primera versión que lo activó por defecto). No necesita prefijo.
  • Safari (escritorio e iOS) – Requiere el prefijo -webkit- para propiedades de máscara hasta Safari 15.4. Desde Safari 15.4 y iOS 15.4 en adelante, mask-image sin prefijo debería funcionar (Mask-image - CSS - W3cubDocs). En la práctica, siempre incluye el prefijo -webkit- para usuarios con versiones ligeramente antiguas, ya que muchos no están en la última.
  • Edge – EdgeHTML (el antiguo Edge) no soportaba máscaras. El Edge moderno (basado en Chromium, v79+) hereda el soporte de Chrome, incluyendo la necesidad del prefijo en versiones anteriores.
  • Opera – También basado en Chromium, por lo tanto misma historia que Chrome (y versiones antiguas como Opera 15+ usaban máscaras con prefijo -webkit).
  • Navegadores móviles – El navegador Android/WebView siguió la implementación de Chrome (con prefijos WebKit en Android 4.x y sin prefijo actualmente). Firefox para Android las soporta igual que en escritorio. Samsung Internet (también basado en Chromium) soporta máscaras desde la versión 4.0+ (con prefijo -webkit- en versiones anteriores).

En resumen, para máxima compatibilidad: usa la propiedad estándar mask-image y también incluye -webkit-mask-image (y las propiedades relacionadas como -webkit-mask-size, etc.) (Masking images in CSS with the mask-image property - LogRocket Blog). Este enfoque doble cubre Safari y navegadores WebKit antiguos. Los navegadores modernos simplemente ignorarán la versión con prefijo o la estándar según corresponda. También considera usar feature queries o una degradación elegante, como se mencionó en las Buenas Prácticas. Como el soporte ahora es muy amplio, usar mask-image es cada vez más seguro — simplemente excluye IE de tus planes o asegúrate de que no se rompa la experiencia allí.

Referencias externas

Para lectura adicional y documentación oficial sobre mask-image y conceptos relacionados, consulta estos recursos:

SEO Keywords

  • CSS mask-image
  • CSS masking techniques
  • clip-path vs mask-image
  • image masking in web design
  • CSS mask examples and usage