Sombras
Los tokens de sombras definen valores consistentes para dar profundidad y elevación a los elementos de la interfaz.
En Tiendana Design System, preferimos usar tonalidades de colores de superficie para comunicar elevación en lugar de sombras. Las sombras están reservadas para casos específicos como modales, drawers y elementos flotantes que necesitan separación clara del contenido.
Para elevación general de componentes (tarjetas, paneles), usa los colores de fondo de la escala de grises.
Escala de Sombras
Sistema de sombras para casos específicos donde se requiere separación visual pronunciada:
| Token | Uso Permitido | Cuándo Usar |
|---|---|---|
shadow-none | Elementos planos | Por defecto en la mayoría de componentes |
shadow-sm | Hover sutil | Estados interactivos opcionales |
shadow-md | Dropdowns, tooltips | Menús flotantes sobre contenido |
shadow-lg | Modales, popovers | Diálogos que deben destacar claramente |
shadow-xl | Drawers, side panels | Paneles laterales sobre contenido principal |
shadow-2xl | Splash screens | Elementos excepcionales de máxima prominencia |
Las variables CSS --shadow-sm, --shadow-md, --shadow-lg, --shadow-xl y --shadow-2xl se exportan en :root. Los tokens $shadow-xs (0 1px 2px 0 rgba(0, 0, 0, 0.05)), $shadow-inner (inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)) y $shadow-none existen solo como variables SCSS, y $shadows es el mapa para iterar sobre todos. Para quitar una sombra en CSS usa box-shadow: none o la clase .shadow-none.
Para crear jerarquía visual en tarjetas, paneles y contenedores:
- Usa colores de fondo de la escala de grises (
gray-100,gray-200, etc.) - Combina con bordes sutiles (
border-color) - Reserva las sombras solo para overlays (modales, drawers, dropdowns)
Valores de Sombras
/* Pequeña - Hover sutil */
--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1),
0 1px 2px 0 rgba(0, 0, 0, 0.06);
/* Mediana - Tarjetas */
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
/* Grande - Modales */
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
/* Extra grande - Drawers */
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
/* Doble extra grande - Elementos prominentes */
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
Uso
- CSS/HTML
- Angular
- Flutter
Variables CSS
:root {
/* Sombras por Elevación */
--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
Ejemplos de uso
/* ✅ Correcto - Tarjeta con color de superficie */
.card {
background: var(--color-gray-100);
border: var(--border-width-thin) solid var(--border-color);
border-radius: var(--border-radius-lg);
padding: var(--spacing-md);
/* NO box-shadow */
}
/* ✅ Correcto - Tarjeta con hover cambia color */
.card-interactive {
background: var(--color-gray-100);
border: var(--border-width-thin) solid var(--border-color);
transition: background-color 0.2s ease;
}
.card-interactive:hover {
background: var(--color-gray-200);
}
/* ✅ Correcto - Dropdown con sombra (overlay) */
.dropdown {
background: white;
border-radius: var(--border-radius-md);
box-shadow: var(--shadow-md);
padding: var(--spacing-sm);
}
/* ✅ Correcto - Modal con sombra (overlay) */
.modal {
background: white;
border-radius: var(--border-radius-2xl);
padding: var(--spacing-xl);
box-shadow: var(--shadow-lg);
}
/* ✅ Correcto - Drawer con sombra (overlay) */
.drawer {
background: white;
box-shadow: var(--shadow-xl);
padding: var(--spacing-lg);
}
/* ✅ Correcto - FAB con sombra (flotante) */
.fab {
width: 56px;
height: 56px;
border-radius: var(--border-radius-circle);
box-shadow: var(--shadow-md);
background: var(--color-natura);
transition: box-shadow 0.2s ease;
}
.fab:hover {
box-shadow: var(--shadow-lg);
}
/* ✅ Correcto - Panel con color de superficie */
.panel {
background: var(--color-gray-200);
border: var(--border-width-thin) solid var(--border-color);
border-radius: var(--border-radius-lg);
padding: var(--spacing-lg);
/* NO box-shadow */
}
Variables CSS
:root {
/* Sombras por Elevación */
--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
Ejemplos de uso
// En estilos de componente
@Component({
selector: 'app-card',
styles: [`
.card {
background: white;
border-radius: var(--border-radius-lg);
padding: var(--spacing-md);
box-shadow: var(--shadow-md);
transition: box-shadow 0.2s ease;
}
.card:hover {
box-shadow: var(--shadow-lg);
}
`]
})
export class CardComponent {}
// En archivos SCSS usando tokens de WebFoundation
@use '@tiendana/web-foundation' as tdn;
.my-card {
background: white;
border-radius: tdn.$border-radius-lg;
padding: tdn.$spacing-md;
// Usar variable SCSS directamente
box-shadow: tdn.$shadow-md;
transition: box-shadow 0.2s ease;
&:hover {
box-shadow: tdn.$shadow-lg;
}
}
.modal {
background: white;
border-radius: tdn.$border-radius-2xl;
padding: tdn.$spacing-xl;
box-shadow: tdn.$shadow-lg;
}
.dropdown {
background: white;
border-radius: tdn.$border-radius-md;
box-shadow: tdn.$shadow-md;
}
// O usar CSS variables
.other-component {
box-shadow: var(--shadow-md);
}
Definir Sombras
import 'package:flutter/material.dart';
class TiendanaShadows {
// Sin sombra
static const List<BoxShadow> shadowNone = [];
// Pequeña - Hover sutil
static const List<BoxShadow> shadowSm = [
BoxShadow(
color: Color(0x1A000000), // rgba(0, 0, 0, 0.1)
offset: Offset(0, 1),
blurRadius: 3,
spreadRadius: 0,
),
BoxShadow(
color: Color(0x0F000000), // rgba(0, 0, 0, 0.06)
offset: Offset(0, 1),
blurRadius: 2,
spreadRadius: 0,
),
];
// Mediana - Tarjetas
static const List<BoxShadow> shadowMd = [
BoxShadow(
color: Color(0x1A000000), // rgba(0, 0, 0, 0.1)
offset: Offset(0, 4),
blurRadius: 6,
spreadRadius: -1,
),
BoxShadow(
color: Color(0x0F000000), // rgba(0, 0, 0, 0.06)
offset: Offset(0, 2),
blurRadius: 4,
spreadRadius: -1,
),
];
// Grande - Modales
static const List<BoxShadow> shadowLg = [
BoxShadow(
color: Color(0x1A000000), // rgba(0, 0, 0, 0.1)
offset: Offset(0, 10),
blurRadius: 15,
spreadRadius: -3,
),
BoxShadow(
color: Color(0x0D000000), // rgba(0, 0, 0, 0.05)
offset: Offset(0, 4),
blurRadius: 6,
spreadRadius: -2,
),
];
// Extra grande - Drawers
static const List<BoxShadow> shadowXl = [
BoxShadow(
color: Color(0x1A000000), // rgba(0, 0, 0, 0.1)
offset: Offset(0, 20),
blurRadius: 25,
spreadRadius: -5,
),
BoxShadow(
color: Color(0x0A000000), // rgba(0, 0, 0, 0.04)
offset: Offset(0, 10),
blurRadius: 10,
spreadRadius: -5,
),
];
// Doble extra grande - Elementos prominentes
static const List<BoxShadow> shadowXl2 = [
BoxShadow(
color: Color(0x40000000), // rgba(0, 0, 0, 0.25)
offset: Offset(0, 25),
blurRadius: 50,
spreadRadius: -12,
),
];
}
Ejemplos de uso
// Tarjeta con sombra
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: TiendanaBorders.radiusLg,
boxShadow: TiendanaShadows.shadowMd,
),
padding: EdgeInsets.all(TiendanaSpacing.md),
child: Text('Contenido de tarjeta'),
)
// Modal con sombra grande
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: TiendanaBorders.radiusXl2,
boxShadow: TiendanaShadows.shadowLg,
),
padding: EdgeInsets.all(TiendanaSpacing.xl),
child: Column(
children: [
Text('Modal'),
],
),
)
// Botón flotante (FAB)
Container(
width: 56,
height: 56,
decoration: BoxDecoration(
color: TiendanaColors.natura,
shape: BoxShape.circle,
boxShadow: TiendanaShadows.shadowMd,
),
child: Icon(Icons.add, color: Colors.white),
)
// Card Material con elevación personalizada
Card(
elevation: 0, // Deshabilitar elevación por defecto
shape: RoundedRectangleBorder(
borderRadius: TiendanaBorders.radiusLg,
),
child: Container(
decoration: BoxDecoration(
borderRadius: TiendanaBorders.radiusLg,
boxShadow: TiendanaShadows.shadowMd,
),
child: Padding(
padding: EdgeInsets.all(TiendanaSpacing.md),
child: Text('Contenido'),
),
),
)
// Drawer con sombra pronunciada
Drawer(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
boxShadow: TiendanaShadows.shadowXl,
),
child: ListView(
children: [...],
),
),
)
Borde con sombra (--ds-shadow-border)
--ds-shadow-border dibuja un borde de 1px con box-shadow, sin ocupar espacio en el modelo de caja. En modo claro vale 0 0 0 1px var(--color-gray-300); con body.scheme-dark pasa a 0 0 0 1px rgba(var(--color-gray-300-rgb), 0.6).
.panel {
box-shadow: var(--ds-shadow-border);
}
Clases de utilidad
.shadow-sm, .shadow-md, .shadow-lg, .shadow-xl, .shadow-2xl y .shadow-none aplican box-shadow con estos tokens. Ver Utilidades CSS.
Cuándo Usar Sombras vs Colores de Superficie
✅ Usa Sombras Para:
- Modales: Diálogos que flotan sobre todo el contenido
- Drawers: Paneles laterales deslizables
- Dropdowns: Menús desplegables sobre contenido
- Tooltips: Información flotante contextual
- Popovers: Contenido emergente temporal
- FAB: Botones de acción flotantes
❌ NO Uses Sombras Para:
- Tarjetas: Usa
background: var(--color-gray-100)+border - Paneles: Usa tonalidades de grises para diferenciar niveles
- Botones: Usa colores sólidos sin sombras
- Chips/Badges: Mantén planos con bordes
- Contenedores generales: Prefiere color de fondo
Patrones por Tipo de Componente
Overlays (Uso Permitido)
- Dropdowns:
shadow-md - Tooltips:
shadow-md - Popovers:
shadow-lg - Modales:
shadow-lgoshadow-xl - Drawers:
shadow-xl - FAB (Floating Action Button):
shadow-md
Contenedores (Usar Color en Lugar de Sombra)
/* ✅ Preferido - Usar color de superficie */
.card {
background: var(--color-gray-100);
border: var(--border-width-thin) solid var(--border-color);
border-radius: var(--border-radius-lg);
/* NO box-shadow */
}
.panel {
background: var(--color-gray-200);
border: var(--border-width-thin) solid var(--border-color);
/* Elevación comunicada por color más oscuro */
}
/* ❌ Evitar - No usar sombras en contenedores */
.card-wrong {
background: white;
box-shadow: var(--shadow-md); /* Incorrecto */
}
Estados Interactivos
- Hover en overlays: Incrementar sombra un nivel
- Hover en tarjetas: Cambiar color de fondo, NO sombra
- Active/Press: Sin cambios de sombra
- Disabled:
shadow-none
Guías de Uso
✅ Mejores Prácticas
- Usa sombras SOLO para overlays (modales, drawers, dropdowns)
- Usa colores de superficie para elevación de tarjetas y paneles
- Incrementa sombra en hover solo en overlays flotantes
- Mantén consistencia: overlay similar = sombra similar
- Usa transiciones suaves (
transition: box-shadow 0.2s ease) - Combina color + borde para jerarquía sin sombras
❌ Evita
- Sombras en tarjetas, paneles o contenedores (usa color)
- Sombras en botones (usa colores sólidos)
- Múltiples niveles de sombra en elementos anidados
- Sombras como único indicador de jerarquía
- Mezclar valores hardcodeados con tokens
- Cambios bruscos de sombra sin transición
Jerarquía de Elevación
Para Overlays (Usa Sombras)
┌────────────────────────────────────────┐
│ shadow-2xl - Splash screens │ Nivel 6 (Excepcional)
├────────────────────────────────────────┤
│ shadow-xl - Drawers │ Nivel 5
├────────────────────────────────────────┤
│ shadow-lg - Modales, popovers │ Nivel 4
├────────────────────────────────────────┤
│ shadow-md - Dropdowns, tooltips, FAB │ Nivel 3 (Común para overlays)
├────────────────────────────────────────┤
│ shadow-sm - Hover en overlays │ Nivel 2
├────────────────────────────────────────┤
│ shadow-none - Elementos planos │ Nivel 1 (Por defecto)
└────────────────────────────────────────┘
Para Contenedores (Usa Color de Superficie)
┌────────────────────────────────────────┐
│ --color-forrest - Más destacado │ Color más oscuro
├────────────────────────────────────────┤
│ --color-gray-600 - Muy elevado │
├────────────────────────────────────────┤
│ --color-gray-400 - Elevado │
├────────────────────────────────────────┤
│ --color-gray-300 - Media elevación │
├────────────────────────────────────────┤
│ --color-gray-200 - Ligeramente elevado │
├────────────────────────────────────────┤
│ --color-gray-100 - Superficie base │ Color más claro (común)
├────────────────────────────────────────┤
│ --color-trust (white) - Fondo │ Sin elevación
└────────────────────────────────────────┘
Accesibilidad
- Las sombras no deben ser el único indicador de estado
- Combina sombras con cambios de color o borde para mejor accesibilidad
- Asegura suficiente contraste entre el elemento y su sombra
- Evita sombras que puedan confundir límites de elementos interactivos
Transiciones
/* Transición suave recomendada */
.element {
box-shadow: var(--shadow-sm);
transition: box-shadow 0.2s ease;
}
.element:hover {
box-shadow: var(--shadow-md);
}
/* Transición más rápida para interacciones */
.button {
box-shadow: var(--shadow-md);
transition: box-shadow 0.15s ease-in-out;
}
.button:active {
box-shadow: var(--shadow-sm);
}