Shadow (sombra) es un efecto visual en interfaces móviles que crea la ilusión de profundidad y jerarquía entre elementos. Las sombras muestran qué elemento está más arriba en el plano z y, por lo tanto, es más importante o interactivo. Según las Material Design Guidelines (Google, 2026), las sombras del sistema utilizan cinco niveles clave de elevation: 0 dp (plano), 1–4 dp (botones), 6–12 dp (tarjetas), 16–24 dp (diálogos), 24+ dp (ventanas modales). Más información sobre la altura de elementos en el artículo sobre Elevation.
Lo más importante
La sombra (shadow) en las interfaces de usuario es un efecto visual que simula iluminación y profundidad. La sombra se crea dibujando una copia oscura y borrosa de un elemento, desplazada respecto al original. En el diseño móvil, las sombras cumplen tres funciones: muestran jerarquía (cuanto más alto el elemento, más larga la sombra), señalan interactividad (los botones con sombra parecen pulsables), separan el contenido del fondo (las tarjetas con sombra se leen como bloques independientes).
En Material Design de Google, las sombras están inextricablemente vinculadas al concepto de elevation. Cada elemento ocupa una altura determinada en la coordenada z, y la sombra es una proyección de la iluminación superior. Las Human Interface Guidelines de Apple no prescriben un sistema estricto de alturas, pero recomiendan usar sombras para crear jerarquía visual y profundidad en las interfaces.
Según un estudio de Nielsen Norman Group (2024), las sombras colocadas correctamente reducen el tiempo para encontrar un elemento interactivo en un 24%. Las sombras también ayudan a los usuarios con discapacidad visual a distinguir los límites de los elementos. Sin embargo, el uso excesivo de sombras (3+ niveles en una pantalla) aumenta la carga cognitiva y perjudica la percepción.
En iOS, las sombras se implementan mediante propiedades de CALayer: shadowColor define el color de la sombra, shadowOffset — desplazamiento en CGSize (x, y), shadowRadius — radio de desenfoque, shadowOpacity — opacidad de 0 a 1. Para rendimiento, también se recomienda establecer shadowPath — un UIBezierPath que describe la forma de la sombra, para que Core Animation no la calcule automáticamente.
// UIKit: configuración de sombra mediante CALayer
import UIKit
let cardView = UIView()
cardView.backgroundColor = .systemBackground
cardView.layer.cornerRadius = 12
// Configuración de sombra
cardView.layer.shadowColor = UIColor.black.cgColor
cardView.layer.shadowOpacity = 0.15
cardView.layer.shadowOffset = CGSize(width: 0, height: 4)
cardView.layer.shadowRadius = 8
"> Optimización: shadowPath explícito
cardView.layer.shadowPath = UIBezierPath(
roundedRect: cardView.bounds,
cornerRadius: 12
).cgPath
En SwiftUI, las sombras se definen mediante el modificador .shadow() con parámetros color, radius, x, y. SwiftUI aplica automáticamente shadowPath y gestiona el rendimiento de renderizado. Para sombras avanzadas (sombras interiores, múltiples sombras), use overlay() con LinearGradient.
// SwiftUI: sombra mediante el modificador shadow
import SwiftUI
VStack {
Text("Tarjeta con sombra")
.padding()
.background(Color.white)
.cornerRadius(16)
.shadow(
color: .black.opacity(0.15),
radius: 10,
x: 0,
y: 4
)
}
Rendimiento de sombras en iOS: si no se establece shadowPath, Core Animation calcula la sombra basándose en la forma de la capa cada fotograma, lo que puede causar retrasos durante la animación. Para elementos estáticos, establezca siempre shadowPath. Para elementos animados, use shouldRasterize = true en CALayer para almacenar en caché la sombra en una capa separada. En SwiftUI, la rasterización se gestiona mediante .drawingGroup().
En Android, las sombras en Material Design se implementan mediante elevation — una propiedad de View que establece la altura del elemento en la coordenada z. El sistema renderiza automáticamente una sombra basada en elevation y outlineProvider (contorno del elemento). Cuanto mayor es la elevation, más grande y borrosa es la sombra. Para vistas que no heredan de Material Design (por ejemplo, AppCompat), las sombras solo funcionan con aceleración de hardware habilitada.
<!-- XML: elevation mediante atributos -->
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp"
app:cardElevation="6dp">
<!-- Contenido de la tarjeta -->
</androidx.cardview.widget.CardView>
Para sombras personalizadas en el sistema de vistas de Android, use OutlineProvider. ViewOutlineProvider permite establecer una forma arbitraria mediante outline.setRoundRect() o outline.setPath(). Sin OutlineProvider, la sombra se renderiza basándose en la forma rectangular de la vista, lo que no tiene en cuenta el redondeo de esquinas.
// Kotlin: OutlineProvider personalizado para sombra
import android.graphics.Outline
import android.view.View
import android.view.ViewOutlineProvider
val myView: View = findViewById(R.id.myView)
myView.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(
0, 0, view.width, view.height,
12f // radio de esquina
)
}
}
myView.elevation = 8f // altura de sombra en px
myView.translationZ = 4f // altura adicional al presionar
En Jetpack Compose, las sombras se gestionan mediante Modifier.shadow() y elevation en los componentes Card y Surface. Modifier.shadow() acepta elevation y shape. A diferencia del sistema de vistas, Compose renderiza las sombras en su propio pipeline de renderizado, proporcionando un comportamiento más predecible en todas las versiones de Android.
// Jetpack Compose: sombra mediante Modifier.shadow
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
Card(
modifier = Modifier.shadow(
elevation = 6.dp,
shape = RoundedCornerShape(12.dp),
clip = false
),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Text("Card con sombra personalizada")
}
El uso correcto de las sombras mejora la percepción de la interfaz, mientras que el uso incorrecto crea ruido visual y degrada el rendimiento. Material Design define cinco niveles de elevation: 0 dp (sin sombra), 1–4 dp (botones, chips), 6–12 dp (tarjetas, menús), 16–24 dp (diálogos, bottom sheets), 24+ dp (ventanas modales, FAB).
| Nivel | Elevation | Elementos | Característica de la sombra |
|---|---|---|---|
| 0 | 0 dp | Texto, iconos, fondo | Sin sombra, capa plana |
| 1 | 1–4 dp | Botones, campos de entrada | Sombra ligera, pequeño desplazamiento |
| 2 | 6–12 dp | Tarjetas, Snackbar | Sombra moderada, desenfoque notable |
| 3 | 16–24 dp | Diálogos, menús | Sombra profunda, gran desenfoque |
| 4 | 24+ dp | Ventanas modales | Sombra máxima, elemento flota |
Buenas prácticas: (1) no use sombras para elementos que no deben atraer atención (fondos, divisores), (2) la altura de la sombra debe coincidir con la importancia del elemento — cuanto más importante, más alta, (3) al presionar un botón, disminuya la elevation con animación para retroalimentación táctil, (4) evite sombras en fondos oscuros — use overlay (aclarar/oscurecer) en lugar de sombra. En Material You (Android 12+), las sombras se adaptan al tema: en fondos oscuros, la elevation se reemplaza por una capa de color (surface tint).
En Flutter, las sombras se implementan mediante BoxShadow dentro de BoxDecoration. BoxShadow acepta color, offset, blurRadius y spreadRadius. Flutter admite múltiples sombras: pasar una lista de BoxShadow permite crear efectos complejos — por ejemplo, una sombra exterior + resalte interior. PhysicalModel es una alternativa que simula una sombra física basada en la forma (BeveledRectangleBorder, CircleBorder).
// Flutter: sombra mediante BoxDecoration + BoxShadow
import 'package:flutter/material.dart';
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.0),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
offset: Offset(0, 4),
blurRadius: 8.0,
spreadRadius: 0,
),
],
),
child: Text('Contenedor con sombra'),
)
// PhysicalModel para sombra física
PhysicalModel(
color: Colors.white,
elevation: 6.0,
shadowColor: Colors.black.withOpacity(0.2),
borderRadius: BorderRadius.circular(12.0),
child: Text('Modelo físico con sombra'),
)
Rendimiento: BoxShadow con múltiples sombras puede causar repintado en cada cambio. Para elementos estáticos, use PhysicalModel — almacena en caché la sombra en una capa separada (RepaintBoundary). En Flutter 3.16+, se admite elevation de Material 3 con sombras adaptativas, que cambian de color y desenfoque según el tema (claro/oscuro).
Preguntas frecuentes
Elevation es la altura numérica de un elemento en la coordenada z, mientras que shadow (sombra) es el efecto visual creado por esta altura. En Android, elevation es una propiedad de View que genera automáticamente una sombra. En diseño, elevation y shadow a menudo se usan indistintamente, pero técnicamente elevation es la causa y shadow es el efecto.
Verifique: (1) la View tiene elevation mayor que 0, (2) se ha establecido outlineProvider (si la View no es de la biblioteca Material), (3) la aceleración de hardware está habilitada (android:hardwareAccelerated="true" en el manifiesto). CardView gestiona automáticamente outlineProvider. Para vistas personalizadas, llame a view.outlineProvider = ViewOutlineProvider.BACKGROUND.
CALayer no admite sombras interiores directamente. Use una combinación: CAGradientLayer con color negro y transparencia dentro de una máscara, o superponga un UIImageView con una sombra interior rasterizada. En SwiftUI, la sombra interior se implementa mediante overlay con LinearGradient y blendMode(.multiply).
En Android, use translationZ para la animación: en reposo elevation = 2 dp, al presionar translationZ = 4 dp (altura total 6 dp). En iOS, anime shadowOffset y shadowRadius simultáneamente con la transformación del botón. En SwiftUI, use withAnimation con cambio de elevation mediante Modifier.shadow(). En Flutter, use AnimatedContainer con cambio de BoxShadow.
Material Design recomienda no más de tres niveles de elevation en una misma pantalla. Si hay más elementos con sombra, agrúpelos con la misma altura. La cantidad excesiva de sombras crea ruido visual y reduce el rendimiento de renderizado en dispositivos de gama media y baja.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también