Skip to content

12. Estilos y CSS

Vue 3 ofrece varias formas de trabajar con estilos CSS, permitiendo tanto estilos encapsulados (scoped) como globales. La Composition API no cambia la forma en que se manejan los estilos en Vue, ya que estos se definen en la sección <style> del componente independientemente del API utilizado.

Los estilos con alcance limitado (scoped) permiten que los estilos CSS definidos en un componente solo afecten a ese componente específico, evitando conflictos con otros componentes.

Componente con estilos scoped
<template>
<div class="container">
<h1>{{ title }}</h1>
<p class="description">{{ description }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const title = ref('Componente con estilos scoped')
const description = ref('Estos estilos solo afectan a este componente')
</script>
<style scoped>
.container {
padding: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}
h1 {
color: #42b883; /* Color verde de Vue */
font-size: 24px;
}
.description {
color: #666;
line-height: 1.5;
}
</style>

Cuando se utiliza el atributo scoped en la etiqueta <style>, Vue añade automáticamente un atributo de datos único (como data-v-7ba5bd90) a todos los elementos HTML del componente y modifica los selectores CSS para que solo se apliquen a elementos con ese atributo.

CSS compilado con scoped
/* Original */
.description { color: #666; }
/* Compilado */
.description[data-v-7ba5bd90] { color: #666; }

Por defecto, los estilos scoped no afectan a los componentes hijos. Para aplicar estilos a componentes hijos desde un componente padre, puedes usar el selector >>> (o :deep() en Vue 3):

Selector :deep() para componentes hijos
<style scoped>
/* Afecta a los elementos .title dentro de componentes hijos */
:deep(.title) {
color: #ff0000;
}
/* Sintaxis alternativa (menos recomendada) */
.parent >>> .child {
color: #ff0000;
}
</style>

Los estilos globales afectan a toda la aplicación y se definen sin el atributo scoped.

Estilos globales en un componente Vue
<style>
/* Estos estilos afectarán a toda la aplicación */
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 0;
background-color: #f5f5f5;
}
.btn {
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.btn-primary {
background-color: #42b883;
color: white;
border: none;
}
</style>
  1. Archivo dedicado: Para estilos globales, es recomendable crear un archivo CSS separado e importarlo en el componente principal de la aplicación (como App.vue).
Importación de estilos globales
// En main.js o main.ts
import { createApp } from 'vue'
import App from './App.vue'
import './assets/styles/global.css' // Importación de estilos globales
createApp(App).mount('#app')
  1. Módulos CSS: Vue también soporta módulos CSS para un mejor encapsulamiento:
Uso de módulos CSS
<template>
<div :class="$style.container">
<h1 :class="$style.title">Título con módulos CSS</h1>
</div>
</template>
<script setup>
// No se requiere configuración adicional en el script para módulos CSS
</script>
<style module>
.container {
padding: 20px;
}
.title {
color: #42b883;
}
</style>

Tailwind CSS es un framework de utilidades CSS que se integra perfectamente con Vue 3. Permite crear interfaces de usuario personalizadas sin salir del HTML mediante clases de utilidad.

Instalación de Tailwind CSS en un proyecto Vue 3

Section titled “Instalación de Tailwind CSS en un proyecto Vue 3”
Instalación con Vue CLI
# Instalar dependencias
npm install -D tailwindcss postcss autoprefixer
# Generar archivos de configuración
npx tailwindcss init -p

Configura los archivos de Tailwind para que reconozca tus archivos Vue:

tailwind.config.js
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}

Crea un archivo CSS principal (por ejemplo, ./src/assets/main.css) e importa Tailwind:

Importación de Tailwind
/* src/assets/main.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Luego importa este archivo en tu punto de entrada principal:

Importación en el punto de entrada
// main.js o main.ts
import { createApp } from 'vue'
import App from './App.vue'
import './assets/main.css'
createApp(App).mount('#app')
Componente Vue con Tailwind CSS
<template>
<div class="min-h-screen bg-gray-100 py-6 flex flex-col justify-center sm:py-12">
<div class="relative py-3 sm:max-w-xl sm:mx-auto">
<div class="relative px-4 py-10 bg-white shadow-lg sm:rounded-3xl sm:p-20">
<h1 class="text-2xl font-bold text-gray-900 mb-4">{{ title }}</h1>
<p class="text-gray-600">{{ description }}</p>
<button class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors">
Click me
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const title = ref('Componente con Tailwind CSS')
const description = ref('Este componente utiliza clases de utilidad de Tailwind CSS')
</script>

La directiva @apply de Tailwind CSS permite extraer patrones comunes de clases de utilidad en estilos personalizados, lo que es especialmente útil en componentes Vue.

Uso de @apply en componentes Vue
<template>
<button class="btn-primary">Botón Primario</button>
<button class="btn-secondary">Botón Secundario</button>
</template>
<script setup>
// No se requiere configuración especial para usar @apply
</script>
<style>
.btn-primary {
@apply px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors;
}
.btn-secondary {
@apply px-4 py-2 bg-gray-300 text-gray-800 rounded hover:bg-gray-400 transition-colors;
}
</style>

Puedes combinar @apply con estilos scoped para mantener el encapsulamiento:

@apply con estilos scoped
<template>
<div class="card">
<h2 class="card-title">{{ title }}</h2>
<p class="card-content">{{ content }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const title = ref('Tarjeta con @apply')
const content = ref('Contenido de la tarjeta usando @apply con estilos scoped')
</script>
<style scoped>
.card {
@apply bg-white rounded-lg shadow-md p-6 max-w-md mx-auto;
}
.card-title {
@apply text-xl font-bold text-gray-800 mb-2;
}
.card-content {
@apply text-gray-600;
}
</style>

Creación de componentes con @apply 🐧🍿

Section titled “Creación de componentes con @apply 🐧🍿”

Puedes crear componentes reutilizables usando @apply en un archivo CSS global:

Componentes con @apply
/* src/assets/components.css */
@layer components {
.btn {
@apply px-4 py-2 rounded font-medium focus:outline-none focus:ring-2 focus:ring-opacity-50 transition-colors;
}
.btn-primary {
@apply btn bg-blue-500 text-white hover:bg-blue-600 focus:ring-blue-500;
}
.btn-danger {
@apply btn bg-red-500 text-white hover:bg-red-600 focus:ring-red-500;
}
.input {
@apply px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500;
}
.card {
@apply bg-white rounded-lg shadow-md overflow-hidden;
}
.card-header {
@apply px-6 py-4 border-b border-gray-200;
}
.card-body {
@apply p-6;
}
}

Luego importa este archivo en tu CSS principal:

Importación de componentes personalizados
/* src/assets/main.css */
@tailwind base;
@tailwind components;
@import "./components.css";
@tailwind utilities;
  1. Reduce el tamaño del HTML: Evita tener largas cadenas de clases en tus templates.
  2. Mejora la legibilidad: Crea nombres de clases semánticos que describen su propósito.
  3. Reutilización: Define estilos una vez y úsalos en múltiples componentes.
  4. Mantenibilidad: Centraliza los cambios de estilo en un solo lugar.
  5. Compatibilidad con scoped: Funciona perfectamente con el sistema de estilos encapsulados de Vue.
🐝