Directiva ngStyle
La directiva ngStyle permite aplicar estilos CSS inline de forma dinámica en elementos HTML, basándose en el estado de nuestro componente. A diferencia de las clases CSS estáticas, ngStyle nos permite modificar propiedades específicas de estilo según las variables o condiciones de nuestro componente.
Sintaxis básica
La directiva ngStyle acepta un objeto JavaScript donde las claves son propiedades CSS y los valores son las expresiones que queremos aplicar:
// app.component.ts
import { Component } from '@angular/core';
import { NgStyle } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [NgStyle],
template: `
<div [ngStyle]="estilosDiv">
Contenido con estilos dinámicos
</div>
`
})
export class AppComponent {
estilosDiv = {
'background-color': 'lightblue',
'font-size': '18px',
'padding': '20px'
};
}
Diferentes formas de definir estilos
Podemos definir los estilos de múltiples maneras según nuestras necesidades:
1 - Con propiedades CSS en camelCase:
estilosConCamelCase = {
backgroundColor: 'lightgreen',
fontSize: '16px',
marginTop: '10px'
};
2 - Con propiedades CSS en kebab-case (entre comillas):
estilosConKebabCase = {
'background-color': 'lightcoral',
'font-size': '16px',
'margin-top': '10px'
};
3 - Directamente en el template:
<div [ngStyle]="{
'color': isActive ? 'green' : 'red',
'font-weight': isImportant ? 'bold' : 'normal'
}">
Texto con estilos condicionales
</div>
Manejo de unidades CSS
NgStyle maneja automáticamente las unidades CSS cuando trabajamos con valores numéricos, pero también podemos especificarlas explícitamente:
// app.component.ts
export class AppComponent {
tamañoElemento = 150;
margenElemento = 20;
estilosConUnidades = {
width: this.tamañoElemento + 'px', // Unidad explícita
height: this.tamañoElemento + 'px',
margin: this.margenElemento + 'px',
'border-width': '2px', // Unidad en string
'border-style': 'solid'
};
}
En el template, podemos usar estos estilos así:
<div [ngStyle]="estilosConUnidades" class="elemento">
Elemento con dimensiones dinámicas
</div>
Estilos condicionales
Una de las ventajas principales de ngStyle es poder aplicar estilos según condiciones:
export class AppComponent {
temperatura = 25;
isVisible = true;
get estilosTemperatura() {
return {
'background-color': this.temperatura > 30 ? 'red' :
this.temperatura > 20 ? 'orange' : 'blue',
'color': 'white',
'display': this.isVisible ? 'block' : 'none',
'font-size': '20px'
};
}
}
<div [ngStyle]="estilosTemperatura">
Temperatura: {{ temperatura }}°C
</div>
Comparación con [style] binding
Angular también ofrece property binding para estilos individuales usando la sintaxis [style.propiedad]
:
<!-- Con ngStyle -->
<div [ngStyle]="{'color': textColor, 'font-size': fontSize + 'px'}">
Texto con ngStyle
</div>
<!-- Con style binding -->
<div [style.color]="textColor" [style.font-size.px]="fontSize">
Texto con style binding
</div>
Cuándo usar cada uno:
- [style] es ideal para modificar una sola propiedad CSS
- ngStyle es mejor cuando necesitas aplicar múltiples estilos relacionados o usar lógica compleja
Consideraciones importantes
Aunque ngStyle es una herramienta útil, debemos usarla con moderación. Los estilos inline tienen mayor especificidad que las clases CSS y pueden hacer que nuestro código sea más difícil de mantener.
Recomendaciones:
- Usa clases CSS para estilos estáticos y diseño general
- Reserva ngStyle para valores realmente dinámicos como colores basados en datos, dimensiones calculadas o estilos que cambian según el estado de la aplicación
- Considera crear clases CSS condicionales con ngClass cuando sea posible
// Mejor práctica: combinar clases CSS con ngStyle
export class AppComponent {
progreso = 65;
get estilosProgreso() {
return {
'width': this.progreso + '%' // Solo el valor dinámico
};
}
}
<div class="barra-progreso">
<div class="progreso-fill" [ngStyle]="estilosProgreso"></div>
</div>
En este enfoque, los estilos base se definen en CSS y solo usamos ngStyle para las propiedades que realmente necesitan ser dinámicas.
Estilos CSS dinámicos
Los estilos CSS dinámicos van más allá de la aplicación básica de propiedades, permitiendo crear interfaces que responden de forma inteligente a las interacciones del usuario y al estado de la aplicación. Esta aproximación nos permite construir componentes verdaderamente reactivos que adaptan su apariencia según el contexto.
Estilos basados en interacciones del usuario
Podemos crear estilos que respondan a las acciones del usuario combinando event binding con ngStyle:
export class AppComponent {
mouseX = 0;
mouseY = 0;
isHovered = false;
clickCount = 0;
onMouseMove(event: MouseEvent) {
this.mouseX = event.clientX;
this.mouseY = event.clientY;
}
onHover(hovering: boolean) {
this.isHovered = hovering;
}
onClick() {
this.clickCount++;
}
get estilosSeguimiento() {
return {
'transform': `translate(${this.mouseX / 10}px, ${this.mouseY / 10}px)`,
'background-color': this.isHovered ? '#ff6b6b' : '#4ecdc4',
'scale': this.clickCount > 5 ? '1.2' : '1.0',
'transition': 'all 0.3s ease'
};
}
}
<div class="area-interactiva"
(mousemove)="onMouseMove($event)"
(mouseenter)="onHover(true)"
(mouseleave)="onHover(false)"
(click)="onClick()">
<div class="elemento-seguidor" [ngStyle]="estilosSeguimiento">
Elemento reactivo (clicks: {{ clickCount }})
</div>
</div>
Cálculos dinámicos complejos
Los estilos dinámicos brillan cuando necesitamos realizar cálculos basados en múltiples variables:
export class DashboardComponent {
datos = [
{ nombre: 'Ventas', valor: 85, meta: 100 },
{ nombre: 'Marketing', valor: 92, meta: 90 },
{ nombre: 'Soporte', valor: 78, meta: 85 }
];
calcularEstilosBarra(item: any) {
const porcentaje = (item.valor / item.meta) * 100;
const colorBase = porcentaje >= 100 ? 'green' :
porcentaje >= 80 ? 'orange' : 'red';
return {
'width': Math.min(porcentaje, 100) + '%',
'background': `linear-gradient(90deg, ${colorBase}, ${colorBase}aa)`,
'box-shadow': porcentaje > 100 ? '0 0 10px gold' : 'none',
'transition': 'all 0.5s ease-in-out'
};
}
calcularEstilosTexto(item: any) {
const porcentaje = (item.valor / item.meta) * 100;
return {
'color': porcentaje >= 100 ? '#2d5a27' : '#333',
'font-weight': porcentaje >= 100 ? 'bold' : 'normal'
};
}
}
@for (item of datos; track item.nombre) {
<div class="metrica">
<h3 [ngStyle]="calcularEstilosTexto(item)">{{ item.nombre }}</h3>
<div class="barra-contenedor">
<div class="barra-progreso" [ngStyle]="calcularEstilosBarra(item)"></div>
</div>
<span>{{ item.valor }}/{{ item.meta }}</span>
</div>
}
Estilos temporales y animaciones CSS
NgStyle permite crear efectos temporales que se activan y desactivan programáticamente:
export class NotificacionComponent {
mensajes: string[] = [];
animandoMensaje = false;
agregarMensaje(texto: string) {
this.mensajes.push(texto);
this.animandoMensaje = true;
// Resetear animación después de un tiempo
setTimeout(() => {
this.animandoMensaje = false;
}, 600);
}
get estilosNotificacion() {
return {
'transform': this.animandoMensaje ? 'scale(1.1) rotate(2deg)' : 'scale(1)',
'background-color': this.animandoMensaje ? '#ffd93d' : '#f8f9fa',
'box-shadow': this.animandoMensaje ? '0 5px 15px rgba(255, 217, 61, 0.4)' : 'none',
'transition': 'all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)'
};
}
eliminarMensaje(indice: number) {
this.mensajes.splice(indice, 1);
}
}
Estilos adaptativos según datos
Una aplicación común es adaptar estilos según el tipo o cantidad de datos que manejamos:
export class ListaProductosComponent {
productos = [
{ nombre: 'Laptop', precio: 1200, stock: 5, categoria: 'tecnologia' },
{ nombre: 'Silla', precio: 150, stock: 0, categoria: 'muebles' },
{ nombre: 'Libro', precio: 25, stock: 50, categoria: 'libros' }
];
obtenerEstilosProducto(producto: any) {
const sinStock = producto.stock === 0;
const stockBajo = producto.stock > 0 && producto.stock < 10;
return {
'opacity': sinStock ? '0.5' : '1',
'border-left': `4px solid ${this.obtenerColorCategoria(producto.categoria)}`,
'background-color': sinStock ? '#ffebee' :
stockBajo ? '#fff3e0' : '#f1f8e9',
'filter': sinStock ? 'grayscale(50%)' : 'none'
};
}
obtenerEstilosPrecio(precio: number) {
return {
'font-size': precio > 1000 ? '1.4em' : '1em',
'color': precio > 1000 ? '#d32f2f' : '#388e3c',
'font-weight': precio > 1000 ? 'bold' : 'normal'
};
}
private obtenerColorCategoria(categoria: string): string {
const colores: {[key: string]: string} = {
'tecnologia': '#2196f3',
'muebles': '#795548',
'libros': '#9c27b0'
};
return colores[categoria] || '#757575';
}
}
@for (producto of productos; track producto.nombre) {
<div class="producto-card" [ngStyle]="obtenerEstilosProducto(producto)">
<h3>{{ producto.nombre }}</h3>
<p class="precio" [ngStyle]="obtenerEstilosPrecio(producto.precio)">
${{ producto.precio }}
</p>
<p class="stock">Stock: {{ producto.stock }}</p>
</div>
}
Optimización de estilos dinámicos
Para mejorar el rendimiento cuando trabajamos con estilos dinámicos frecuentes, podemos usar técnicas de optimización:
export class ComponenteOptimizado {
private estilosCache = new Map<string, any>();
calcularEstilosConCache(clave: string, datos: any) {
if (this.estilosCache.has(clave)) {
return this.estilosCache.get(clave);
}
const estilos = {
'background-color': datos.activo ? '#4caf50' : '#f5f5f5',
'transform': `translateY(${datos.posicion}px)`,
'z-index': datos.prioridad
};
this.estilosCache.set(clave, estilos);
return estilos;
}
// Limpiar cache cuando sea necesario
limpiarCache() {
this.estilosCache.clear();
}
}
Integración con el ciclo de vida del componente
Los estilos dinámicos pueden evolucionar durante el ciclo de vida del componente:
export class ComponenteEvolutivo implements OnInit, OnDestroy {
tiempoTranscurrido = 0;
private intervalo?: number;
ngOnInit() {
this.intervalo = window.setInterval(() => {
this.tiempoTranscurrido++;
}, 1000);
}
ngOnDestroy() {
if (this.intervalo) {
clearInterval(this.intervalo);
}
}
get estilosEvolutivos() {
const fase = Math.floor(this.tiempoTranscurrido / 10) % 3;
const colores = ['#ff6b6b', '#4ecdc4', '#45b7d1'];
return {
'background-color': colores[fase],
'border-radius': (this.tiempoTranscurrido % 20) * 2 + 'px',
'opacity': 0.7 + (Math.sin(this.tiempoTranscurrido * 0.1) * 0.3)
};
}
}
Esta aproximación nos permite crear interfaces verdaderamente dinámicas que responden no solo a la interacción del usuario, sino también al paso del tiempo y a los cambios de estado de la aplicación.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Angular
Documentación oficial de Angular
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Angular
Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la sintaxis y uso básico de la directiva ngStyle en Angular.
- Aprender a definir estilos dinámicos con diferentes formatos y unidades CSS.
- Aplicar estilos condicionales y basados en interacciones del usuario.
- Diferenciar cuándo usar ngStyle frente a binding individual de estilos con [style].
- Optimizar y gestionar estilos dinámicos en el ciclo de vida del componente para mejorar rendimiento y mantenimiento.