Recortes con formas

Funciones web: Máscaras

Descripción general

El enmascaramiento de CSS te permite recortar un elemento con una forma personalizada, como agregar un recorte a una tarjeta o crear un borde con forma. Cuando combines formas para diseños complejos, elige tu estrategia de enmascaramiento según el tipo de contenido que tenga el elemento:

Estrategia de enmascaramiento Uso ideal Impacto del texto
Enmascaramiento de SVG de elementos directos Imágenes, íconos, figuras decorativas y figuras complejas No se recomienda (puede recortar el texto)
Enmascaramiento de SVG de elementos adyacentes Tarjetas con texto, contenido crucial El texto sigue siendo completamente legible.
Pure CSS Gradients Formas geométricas simples No se recomienda (puede recortar el texto)

Implementación

Para implementar recortes con formas, haz lo siguiente:

Cómo usar una máscara de SVG

Las máscaras SVG te permiten definir formas que se restan o se suman al área visible con rellenos blancos (revelar) y negros (ocultar).

Luminancia frente a máscara alfa: Las máscaras SVG se establecen de forma predeterminada en el modo de luminancia (brillo), por lo que usamos fill="white" para revelar áreas y fill="black" para recortarlas. Si prefieres usar la transparencia del SVG (canal alfa) en lugar de los colores, puedes establecer mask-type: alpha; en CSS o mask-type="alpha" en el elemento <mask> del SVG.

Enmascaramiento de SVG de elementos directos

Cuando no hay texto dentro del elemento del que debas preocuparte (como avatares de perfil, imágenes de productos o ilustraciones), puedes aplicar la máscara SVG directamente al elemento.

El uso de maskContentUnits="objectBoundingBox" dentro de la máscara SVG garantiza que la máscara se ajuste automáticamente al ancho y alto de cualquier elemento al que se aplique.

<!-- 1. Define the mask in SVG (hidden from view) -->
<svg width="0" height="0" style="position: absolute;" aria-hidden="true">
  <defs>
    <!-- objectBoundingBox makes the mask scale from 0 to 1 along the element's borders -->
    <mask id="splat-mask" maskContentUnits="objectBoundingBox">
      <!-- Organic Bezier path defining an artistic paint splat shape -->
      <path d="M 0.5 0.05 C 0.58 0.05, 0.58 0.21, 0.67 0.18 C 0.76 0.15, 0.79 0.08, 0.85 0.15 C 0.91 0.22, 0.83 0.32, 0.89 0.38 C 0.95 0.44, 1.03 0.45, 0.99 0.55 C 0.95 0.65, 0.82 0.62, 0.8 0.72 C 0.78 0.82, 0.89 0.92, 0.8 0.97 C 0.71 1.02, 0.64 0.88, 0.55 0.93 C 0.46 0.98, 0.44 1.06, 0.35 1.01 C 0.26 0.96, 0.31 0.81, 0.22 0.79 C 0.13 0.77, 0.01 0.88, 0.01 0.77 C 0.01 0.66, 0.16 0.62, 0.14 0.52 C 0.12 0.42, -0.02 0.39, 0.03 0.29 C 0.08 0.19, 0.23 0.27, 0.29 0.19 C 0.35 0.11, 0.3 0.01, 0.4 0.01 C 0.5 0.01, 0.42 0.05, 0.5 0.05 Z" fill="white" />
    </mask>
  </defs>
</svg>

<!-- 2. Apply the mask to the image element -->
<img src="avatar.jpg" alt="User Profile" class="shaped-avatar">

<style>
.shaped-avatar {
  width: 200px;
  height: 200px;
  object-fit: cover;
  
  /* Apply the SVG mask ID with standard and webkit-prefixed properties */
  -webkit-mask-image: url(#splat-mask);
  mask-image: url(#splat-mask);
}
</style>

Enmascaramiento de SVG de elementos adyacentes

Aplica la máscara a un elemento adyacente en lugar de al elemento superior que contiene texto. Esto garantiza que el texto no se recorte y siga siendo legible.

Para resolver este problema, estructura tu componente en un diseño de dos partes:

  1. Un contenedor de texto seguro y sin enmascarar (.card-body) para todo el contenido legible
  2. Un div decorativo vacío (.card-accent) colocado junto a él, que recibe la máscara SVG personalizada.

Si asignas el mismo color de fondo a ambas partes, se fusionarán visualmente en un solo componente con forma personalizada.

<!-- 1. Define the SVG mask (hidden from view) -->
<svg width="0" height="0" style="position: absolute;" aria-hidden="true">
  <defs>
    <!-- Use objectBoundingBox to make the mask scale with the element -->
    <mask id="accent-stencil" maskContentUnits="objectBoundingBox">
      <!-- Fill the entire area with white (fully visible) -->
      <rect width="1" height="1" fill="white" />
      <!-- Draw a black shape to cut out a concave curve. Extending the path to x=1.1 guarantees it fully clears the right edge, preventing subpixel lines -->
      <path d="M 1.1,0 C 0.4,0.1 0.4,0.9 1.1,1 L 1.1,0 Z" fill="black" />
    </mask>
  </defs>
</svg>

<!-- 2. Create the unified card layout -->
<div class="unified-card">
  <!-- The text-bearing element remains unmasked and perfectly rectangular -->
  <div class="card-body">
    <h3>Premium Membership</h3>
    <p>Get exclusive weekly updates on modern web standards and premium UI designs.</p>
  </div>
  <!-- The empty accent element next to it is masked to form the custom shape -->
  <div class="card-accent"></div>
</div>

<style>
.unified-card {
  display: flex;
  width: 400px;
}

.card-body {
  flex: 1;
  background-color: #1e293b; /* Elegant slate color */
  color: #f8fafc;
  padding: 24px;
  border-top-left-radius: 16px;
  border-bottom-left-radius: 16px;
}

.card-accent {
  width: 60px;
  background-color: #1e293b; /* Same background color so they merge visually without seams */
  border-top-right-radius: 16px;
  border-bottom-right-radius: 16px;

  /* Reference the SVG mask */
  -webkit-mask-image: url(#card-accent-mask);
  mask-image: url(#card-accent-mask);
}
</style>

Usa un solo gradiente de CSS para recortes simples

Cuando solo necesites recortes geométricos simples (como un recorte superior semicircular, sangrías laterales o cortes diagonales rectos), no es necesario que escribas ni hagas referencia a un SVG externo. En su lugar, puedes definir un gradiente radial o lineal de CSS directamente dentro de la propiedad mask-image.

<div class="gradient-masked-card">
  <h3>Notched Coupon Card</h3>
  <p>This card uses a pure CSS radial gradient to cut out a semi-circular notch along its top edge.</p>
</div>

<style>
.gradient-masked-card {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  padding: 40px 24px 24px 24px; /* Extra top padding ensures content clears the notch */
  border-radius: 16px;
  text-align: center;

  /* radial-gradient places a circle at 50% (horizontal center) and 0% (top edge), cutting out a 20px transparent notch */
  -webkit-mask-image: radial-gradient(circle at 50% 0%, transparent 20px, black 21px);
  mask-image: radial-gradient(circle at 50% 0%, transparent 20px, black 21px);
}
</style>

Estrategias de resguardo

Si un navegador no admite mask-image ni la versión con prefijo, haz lo siguiente:

  • Para imágenes con forma: El elemento se degradará de forma correcta y se mostrará como un elemento rectangular normal con sus estilos de resguardo predeterminados.
  • Para las tarjetas con forma: El elemento decorativo .card-accent adyacente seguirá siendo un rectángulo sólido sin máscara. Como comparte el mismo color de fondo que el contenedor de texto, toda la tarjeta se renderizará simplemente como un contenedor rectangular estándar y limpio.
  • Mejora progresiva: Si mantienes las capas de texto completamente fuera de la máscara, se garantiza que el contenido siga siendo completamente legible, estructurado y accesible en navegadores más antiguos.