---
title: "Introducción a las @layer en CSS: Mejora la organización y control de estilos con WordPress"
url: "https://flowtitude.com/layer-css-wordpress-tailwind/"
type: "post"
published: "2025-08-12T09:43:00+02:00"
modified: "2026-11-02T07:49:50+01:00"
author: "Angel Julian"
---

En proyectos WordPress, sobre todo cuando combinamos constructores visuales, hojas de estilo personalizadas y plugins, es fácil que los estilos se conviertan en un rompecabezas difícil de mantener. La buena noticia es que el CSS **no tiene por qué ser un desorden creciente**: podemos estructurarlo para que la cascada sea **predecible**, especialmente cuando usamos Tailwind v4.

Las `@layer` te ayudan a **documentar la intención**: no solo escribes reglas, sino que decides en qué orden deben evaluarse. Esto reduce sobrescrituras, evita depender de `!important` y mejora la colaboración en equipo, porque todos entienden **dónde va cada cosa**

## **Orden en medio del caos**

En WordPress, los estilos llegan desde múltiples orígenes (core, plugins, maquetadores, tu tema…). Si no estableces una **jerarquía explícita**, la cascada decide por ti, y normalmente gana quien carga más tarde o quien mete CSS **sin capa** (o inline). El propósito de `@layer` es **poner orden** y convertir esa mezcla en un sistema **intencional** y **mantenible**. Piensa en capas como *“carriles”* por los que circulan tus estilos: si cada cosa va por su carril, hay menos choques.

## ¿Qué es `@layer` y por qué importa?

`@layer` te permite **definir la cascada de forma explícita** creando capas de estilos. Las reglas básicas:

- A igualdad de origen, importancia y especificidad, **gana la capa declarada más tarde**.
- Los estilos **sin capa** (*unlayered*) **ganan siempre** a los que están en capas, sea cual sea la especificidad (salvo con `!important`, que invierte el orden). Por eso a veces “te gana” Gutenberg o un plugin.
- **Dentro de una misma capa**, manda el orden de aparición (lo último gana).

La ventaja clave es que `@layer` convierte la cascada en **configuración**: fijas un orden *base → componentes → utilidades → custom*, y a partir de ahí todo lo que añadas respeta esa decisión. Pasas de “apagar fuegos” a **diseñar un sistema**. Cuando alguien nuevo entra al proyecto, entiende en minutos **dónde** debe ubicar un ajuste y **por qué**.

## Arquitectura recomendada de capas (WordPress + Tailwind v4)

Define el orden **al principio** de tu hoja principal y mantén pocas capas con responsabilidades claras:

```
@layer base, components, utilities, custom;
```

- **base** → reset/preflight, tipografía global, normalizaciones.
- **components** → patrones reutilizables (.btn, .card, .input…).
- **utilities** → pequeños helpers cuando no exista la utilidad Tailwind.
- **custom** → último recurso para convivir con CSS de terceros (úsalo con moderación).

Menos es más. Cuantas **menos capas** y **más claras** estén sus responsabilidades, **menos deuda técnica** acumulas. Si todo se resuelve con `custom`, a corto plazo “funciona”, pero a medio plazo el proyecto se vuelve opaco. Intenta que `custom` sea la excepción bien documentada, no la norma.

## Tailwind v4: integración por capas (elige **una** opción)

#### **Opción A — Import único (rápida):**

```
@import "tailwindcss";

/* Tras el import, declara el orden de capas */
@layer base, components, utilities, custom;
```

#### **Opción B — Control por capas (fina):**

```
/* Declara el orden primero (theme incluido) */
@layer theme, base, components, utilities, custom;

/* Importa Tailwind en las capas deseadas: sin theme.css no hay colores ni espaciados, y no se generan bg-blue-500 ni p-4 */
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/preflight.css" layer(base);
@import "tailwindcss/utilities.css" layer(utilities);

/* Tus componentes irán más abajo en layer(components) */
```

#### **Tokens con `@theme` (opcional, recomendado):**

```
@theme {
  --font-sans: ui-sans-serif, system-ui, "Helvetica Neue", Arial, sans-serif;
  --color-primary: #1e40af;
  --radius-md: .5rem;
  --spacing: .25rem; /* base de p-1, p-2, gap-4… */
}
```

La **Opción A** es ideal para empezar rápido con Tailwind v4. La **Opción B** da control fino cuando quieres decidir exactamente qué entra en cada capa (por ejemplo, si tu `base` ya establece tipografía y quieres evitar conflictos). Y `@theme` te ofrece un lugar único para definir **tokens** (tipos, colores, radios, espaciados), lo que refuerza la coherencia visual en Bricks/Gutenberg y acelera el trabajo. [Flowtit](https://flowtitude.com/layer-css-wordpress-tailwind/)

## Dónde pegar cada cosa en WordPress

#### Con **WindPress**

1. **WP Admin → WindPress → Files → `main.css`**.
2. Arriba del todo pega, en este orden:
    - (Opcional) **`@theme`** con tus tokens.
    - **Opción A o B** de Tailwind v4 (elige solo una).
    - (Si elegiste A) la línea de **orden de capas**.
3. Más abajo, añade tus capas y componentes:

```
@layer base {
  html { font-family: var(--font-sans, ui-sans-serif); }
  a { text-decoration: none; }
}

@layer components {
  .btn { @apply inline-flex items-center justify-center px-4 py-2 rounded font-medium transition; }
  .btn-primary { @apply bg-[var(--color-primary)] text-white hover:opacity-90; }
  .input { @apply w-full px-3 py-2 border rounded outline-hidden; }
  .input:focus { @apply ring-2 ring-[var(--color-primary)]; }
}

/* Para una utilidad propia que admita variantes (md:, hover:) usa @utility */
@utility text-pretty-wide {
  text-wrap: pretty;
  max-inline-size: 70ch;
}

/* Solo para casos puntuales frente a terceros */
@layer custom {
  /* Ajustes mínimos y documentados */
}
```

Colocar `custom` **al final** garantiza que tus excepciones controladas tengan prioridad, pero evita que esta capa se convierta en “cajón de sastre”. Antes de añadir algo a `custom`, revisa si el problema se debe a **orden de encolado** o a **estilos sin capa** de WordPress/plugins. Arreglar la causa evita parches innecesarios.

## Gutenberg: por qué a veces «te gana» y cómo evitarlo

Gutenberg a menudo inyecta CSS **inline** o carga estilos **sin capa**, que **se imponen** sobre todo lo que tengas en capas, sea cual sea la especificidad. Encolar tu CSS después no lo arregla: o metes lo externo en una capa, o tu ajuste va sin capa.

#### **Opciones prácticas (elige las que te apliquen):**

**Quitar Global Styles si no los usas** (en `functions.php` o mu-plugin):

```
add_action('init', function () {
  remove_action('wp_enqueue_scripts', 'wp_enqueue_global_styles');
});
```

**Cargar estilos de bloques por demanda** (menos CSS global y menos choques):

```
add_filter('should_load_separate_core_block_assets', '__return_true');
```

**Reducir/evitar CSS inline de WordPress** para no competir con tus capas:

```
// 0 = desactiva inline y fuerza archivo; también puedes ajustar el umbral (bytes)
add_filter('styles_inline_size_limit', function () { return 0; });
```

Empieza por **limitar el inline** y por **separar assets**. Con menos CSS global en el aire, menos “sorpresas” tendrás en la cascada. Si aun así te pisan, valora **encapsular** el CSS externo en una capa controlada (ver sección nueva más abajo) antes de recurrir a `custom` o `!important`.

## Encapsular CSS de WordPress y plugins en capas

WordPress **no mete** el CSS del core ni de los plugins en ninguna capa por defecto. Si quieres que lo externo **respete tu jerarquía**, puedes **desencolar** sus estilos y **reencolarlos** dentro de tu capa `wordpress` usando `@import … layer(wordpress)`.

#### ¿Por qué aquí usamos una jerarquía extendida?

En otras partes solemos usar una versión reducida (`@layer base, components, utilities, custom;`).
En esta sección, como tratamos la convivencia con **core, plugins y builder**, añadimos capas extra para **aislar orígenes** y **evitar choques**:

- **`wordpress`** → agrupa **core + plugins** (todo lo externo que encapsulamos). Así queda **debajo** de lo nuestro y no pisa tus reglas.
- **`bricks`** → separa estilos base del **builder** (si usas Bricks). Permite ajustar el builder sin afectar al core ni a tus capas de proyecto. *(Si no usas builder con CSS propio, puedes omitirla.)*
- **`layouts`** → patrones estructurales con **menos especificidad** que `components` (secciones, containers, espaciados macro), para que los componentes puedan dominar sin `!important`.
- **`components`, `utilities`, `custom`** → componentes con nombre, helpers puntuales y **overrides excepcionales** (documentados) respectivamente.

**Orden de capas recomendado en este contexto (ejemplo):**

```
@layer wordpress, bricks, base, layouts, components, utilities, custom;
```

Regla práctica: usa la **reducida** en proyectos simples; usa la **extendida** cuando haya builder y/o conflictos con core/plugins que quieras encapsular.

### Implementación: encapsular estilos en `@layer wordpress`

Un solo snippet que:

- Desencola los *handles* que elijas.
- Genera una hoja `<style>` inline con tu orden de capas y un `@import … layer(wordpress)` por cada URL detectada.

```
<?php
/**
 * Inyecta CSS handles específicos en capas CSS personalizadas
 * Versión completa y mejorada con configuración flexible por capas
 */
if (!defined('ABSPATH')) exit;

add_action('wp_enqueue_scripts', function () {
    // Configuración: Handle => Capa de destino
    $handles_config = [
        // Capa WordPress (core y plugins básicos)
        'wp-block-library' => 'wordpress',
        'wp-block-library-theme' => 'wordpress',
        'global-styles' => 'wordpress', // ojo: no tiene archivo (es CSS en línea) y el bucle lo salta
        'wp-block-navigation' => 'wordpress',
        'wp-block-button' => 'wordpress',

        // Capa de componentes (plugins de UI)
        'woocommerce-general' => 'wordpress',
        'woocommerce-layout' => 'wordpress',
        'woocommerce-smallscreen' => 'wordpress',

        // Ejemplos adicionales
        // 'elementor-frontend' => 'components',
        // 'custom-plugin-styles' => 'utilities',
        // 'gravity-forms' => 'components',
    ];

    // Permitir que otros plugins/temas modifiquen la configuración
    $handles_config = apply_filters('css_layers_handles_config', $handles_config);

    // Opcional: Define orden de capas solo si no lo tienes en Tailwind
    // Déjalo vacío '' si ya lo manejas en tu configuración de Tailwind
    $layer_order = apply_filters('css_layers_order', '');

    global $wp_styles;
    if (!isset($wp_styles)) {
        wp_styles();
    }

    $layers_css = [];
    $processed_handles = [];

    foreach ($handles_config as $handle => $target_layer) {
        // Verificar si el handle existe y está registrado/encolado
        if (!wp_style_is($handle, 'registered') && !wp_style_is($handle, 'enqueued')) {
            continue;
        }

        $style_obj = $wp_styles->registered[$handle] ?? null;
        if (!$style_obj || empty($style_obj->src)) {
            continue;
        }

        // Construir URL absoluta
        $src = $style_obj->src;
        if (preg_match('#^https?://#i', $src)) {
            $url = $src;
        } elseif (str_starts_with($src, '//')) {
            $url = (is_ssl() ? 'https:' : 'http:') . $src;
        } elseif (str_starts_with($src, '/')) {
            $url = home_url($src);
        } else {
            // Relativo al directorio base de WP
            $url = home_url('/' . ltrim($src, '/'));
        }

        // Agregar versioning si existe
        if (!empty($style_obj->ver) && $style_obj->ver !== false) {
            $url = add_query_arg('ver', $style_obj->ver, $url);
        }

        // Agrupar por capa
        if (!isset($layers_css[$target_layer])) {
            $layers_css[$target_layer] = [];
        }
        $layers_css[$target_layer][] = $url;

        // Desencolar y desregistrar
        if (wp_style_is($handle, 'enqueued')) {
            wp_dequeue_style($handle);
        }
        if (wp_style_is($handle, 'registered')) {
            wp_deregister_style($handle);
        }

        $processed_handles[] = $handle;
    }

    // Si no hay handles procesados, salir
    if (empty($layers_css)) {
        return;
    }

    // Construir CSS con @layer e @import
    $css_output = '';

    // Agregar declaración de orden de capas solo si se especifica
    if (!empty($layer_order)) {
        $css_output .= "@layer {$layer_order};\n\n";
    }

    // Generar @import por cada capa
    foreach ($layers_css as $layer => $urls) {
        $css_output .= "/* === Capa: {$layer} === */\n";
        foreach ($urls as $url) {
            $css_output .= "@import url('" . esc_url_raw($url) . "') layer({$layer});\n";
        }
        $css_output .= "\n";
    }

    // Inyectar el CSS inline
    $inline_handle = 'css-layers-injection';
    wp_register_style($inline_handle, false, [], wp_get_theme()->get('Version'));
    wp_enqueue_style($inline_handle);
    wp_add_inline_style($inline_handle, $css_output);

    // Debug: Log handles procesados (solo en desarrollo)
    if (defined('WP_DEBUG') && WP_DEBUG) {
        error_log('CSS Layers - Handles procesados: ' . implode(', ', $processed_handles));
        error_log('CSS Layers - Capas creadas: ' . implode(', ', array_keys($layers_css)));
    }

}, 15); // Prioridad temprana para capturar antes que otros plugins

/**
 * Función helper para agregar handles dinámicamente desde otros plugins/temas
 *
 * @param string $handle Handle del CSS a mover
 * @param string $layer Capa de destino
 *
 * Uso: add_css_to_layer('mi-plugin-css', 'components');
 */
function add_css_to_layer($handle, $layer = 'components') {
    add_filter('css_layers_handles_config', function($config) use ($handle, $layer) {
        $config[$handle] = $layer;
        return $config;
    });
}

/**
 * Función helper para definir el orden de capas desde el tema
 *
 * @param string $order Orden de capas separadas por comas
 *
 * Uso: set_css_layers_order('wordpress, components, utilities, custom');
 */
function set_css_layers_order($order) {
    add_filter('css_layers_order', function() use ($order) {
        return $order;
    });
}

/**
 * Función para obtener información de debug sobre las capas procesadas
 *
 * @return array Array con información de las capas
 */
function get_css_layers_info() {
    static $layers_info = null;

    if ($layers_info === null) {
        $layers_info = [
            'processed_handles' => [],
            'layers_created' => [],
            'css_output' => ''
        ];
    }

    return $layers_info;
}
```

**Notas rápidas para uso:**

- Edita `$handles_config` con los handles a “absorber” (p. ej., `wp-block-library`, `woocommerce-general`…).
- El snippet elimina los `<link>` originales y mete esas hojas **dentro de `@layer wordpress`**.
- Mantén `layouts` y `components` como capas propias **por encima** para evitar peleas.
- Si un plugin añade **inline styles** a su handle, considera un **proxy por handle** (no cabe aquí, pero tu snippet global cubre la mayoría de casos).

## Solución de conflictos: flujo de depuración rápido

- **DevTools → Computed:** identifica **qué regla gana** y **de qué archivo/hook** viene (¿inline? ¿wp-block-library? ¿un plugin?).
- **¿Está sin capa?** Si la regla ganadora es unlayered/inline, decide si puedes **reducir inline** (B), **separar assets** (A) o **reordenar encolado** (D).
- **¿Tu regla está en `components` pero debería ser una excepción?** Mueve solo ese ajuste a `custom` y documenta el motivo.
- **¿Nada de lo anterior es viable?** Usa un **opt-out puntual** (pequeña hoja sin capas) para el override crítico, limita su alcance y evita convertirlo en norma.
- **Repite prueba en páginas reales** (home, blog, producto) y en el editor de bloques.

Piensa en este flujo como una **lista de descarte**: primero ataja la causa (orden/inline), luego valora encapsular en `wordpress`, y solo al final recurre a `custom`. Seguir esta secuencia reduce *hotfixes* y hace que tu CSS sea **sostenible** en el tiempo.

## Buenas prácticas

- **Una única estrategia de import**: A **o** B, nunca ambas.
- **Pocas capas, bien definidas**: base → components → utilities → custom.
- **`@theme` primero**: tokens compartidos para coherencia visual.
- **`overrides` como excepción**: usa selectores simples y ámbito mínimo.
- **Evita `!important`**: suele ocultar problemas de orden/inline.
- **Rendimiento**: preferir assets por demanda y menos inline.
- **Documentación**: anota por qué existe cada override (evita deuda técnica).

Documentar **por qué** existe cada override te ahorra horas cuando vuelves al proyecto meses después. También facilita que otros colaboradores se sumen sin romper nada: ven el histórico y entienden la intención detrás de cada ajuste.

## Errores comunes (y cómo se arreglan)

- **Mezclar Opción A y B** → capas duplicadas/desorden. *Arreglo:* elige una.
- **Creer que encolar al final basta** → si tu CSS está en capas, el CSS sin capa de Gutenberg o de un plugin gana igual. *Arreglo:* mete lo externo en una capa (snippet de arriba) o deja tu ajuste sin capa.
- **Abusar de `custom`** → arquitectura opaca. *Arreglo:* usa custom solo tras ordenar encolado/inline.
- **Crear diez capas** → mantenimiento imposible. *Arreglo:* mantén 3–4 capas.
- **Ignorar inline** → “fantasmas” que te pisan. *Arreglo:* limita inline con `styles_inline_size_limit`.
- **Usar `!important` de forma sistemática** → te encierra. *Arreglo:* arregla orden, no la sintomatología.

Casi siempre que ves `!important` multiplicándose, **falta arquitectura**. Antes de tocar reglas, revisa **dónde** y **cómo** se cargan. Encapsular WordPress/plugins en `wordpress` y reservar `custom` para excepciones puntuales suele eliminar la necesidad de `!important`.

## Checklist de verificación

- Declaraste `@layer base, components, utilities, custom;` al inicio.
- Usas **solo una** estrategia de import v4 (A o B).
- El CSS de plugins/Gutenberg está **dentro de una capa**, o asumes que lo que quede sin capa ganará.
- ¿Has activado **assets por demanda** de bloques si te conviene?
- ¿Has limitado el **inline** de WP si te pisa?
- ¿`overrides` existe pero está acotado y documentado?
- ¿Tokens en `@theme` y estilos globales en `base`?
- ¿Probado en plantillas reales y en el editor?

No hace falta cumplir todo desde el primer día. Empieza por **ordenar el encolado**, añade tu **orden de capas**, limita el **inline**, y deja `custom` casi vacío. Con eso ya notarás un salto en estabilidad. El encapsulado en `wordpress` es el plus cuando un tercero te pisa a menudo.

## Preguntas frecuentes

**¿Por qué mis utilidades de Tailwind no se aplican en páginas con bloques?**
Porque Gutenberg puede inyectar CSS **inline** o sin capa que **se impone siempre** sobre lo que está en `@layer`, tenga la especificidad que tenga. Ordena el encolado, separa assets, limita inline y, si es imprescindible, usa un opt-out puntual sin capas.

**¿Puedo meter todo en `custom` y listo?**
No. Los `overrides` son una **excepción**. Primero arregla el orden de encolado y el inline; solo después añade un ajuste mínimo y documentado.

**¿Qué diferencia hay entre `components` y `utilities`?**
`components` define patrones con nombre (p. ej., `.btn`), mientras `utilities` son pequeños helpers que no ameritan un componente completo. Mantener esa frontera clara evita duplicación y facilita mantenimiento.

**¿`!important` es mala práctica siempre?**
No siempre, pero suele indicar un problema de fondo. Úsalo solo si has agotado orden de encolado, assets por demanda y un override mínimo.

## Conclusión

`@layer` te devuelve el control de la cascada. Con **Tailwind v4** y una arquitectura clara (base → components → utilities → custom), puedes integrar estilos en **WordPress** sin “peleas” con Gutenberg y plugins. Ordena el encolado, reduce inline y usa overrides puntuales: obtendrás un CSS **estable, escalable y fácil de mantener**.

---

**¿Quieres verlo aplicado a tu WordPress?**
En la comunidad **Flowtitude** tienes plantillas, snippets y guías paso a paso para integrar **Tailwind v4 + @layer** en WordPress sin dolores. Únete y accede a los recursos.

[Unirme a Flowtitude 🚀](https://flowtitude.com/crear-cuenta/)
