CSS

Guía completa de capas en cascada CSS trucos CSS

Esta es su guía completa para las capas en cascada de CSS, una función de CSS que nos permite definir explícitamente capas de especificidad para que tengamos un control completo sobre qué estilos tienen prioridad en un proyecto, sin depender de trucos de especificidad o !importantEsta guía tiene como objetivo ayudarlo a comprender completamente para qué sirven las capas en cascada, cómo y por qué puede elegir usarlas, los niveles de soporte actuales y la sintaxis de cómo las usa.

Contenido

Un ejemplo rápido

/* establish a layer order up-front, from lowest to highest priority */
@layer reset, defaults, patterns, components, utilities, overrides;

/* import stylesheets into a layer (dot syntax represents nesting) */
@import url('framework.css') layer(components.framework);

/* add styles to layers */
@layer utilities {
  /* high layer priority, despite low specificity */
  [data-color="brand"] { 
    color: var(--brand, rebeccapurple);
  }
}

@layer defaults {
  /* higher specificity, but lower layer priority */
  a:any-link { color: maroon; }
}

/* un-layered styles have the highest priority */
a {
  color: mediumvioletred;
}

Introducción: ¿qué son las capas en cascada?

Las capas en cascada de CSS están diseñadas para resolver problemas difíciles en CSS. Vamos a ver el problema principal y cómo las capas en cascada pretenden resolverlo.

Problema: Los conflictos de especificidad aumentan

Muchos de nosotros hemos estado en situaciones en las que queremos reemplazar estilos en otras partes de nuestro código (o una herramienta de terceros) debido a selectores en conflicto. A lo largo de los años, los autores han desarrollado una serie de «metodologías» y «mejores prácticas» para evitar estas situaciones, como «usar una sola clase» para todos los selectores. Estas reglas generalmente tratan de evitar la cascada en lugar de usarla.

La gestión de conflictos en cascada y la especificidad del selector a menudo se consideran uno de los aspectos más difíciles, o al menos más confusos, de CSS. Esto puede deberse en parte al hecho de que pocos otros idiomas confían en la cascada como función principal, pero también es cierto que la cascada original dependía en gran medida de heurística (suposición o conjetura incrustada en el código), en lugar de proporcionar un control directo y explícito a los autores web.

Especificidad del selectorpor ejemplo, nuestra principal interacción con la cascada, se basa en la suposición de que los estilos más específicos (como los identificadores que se usan solo una vez) son probablemente más importantes que los estilos más genéricos y reutilizables (como las clases y los atributos). dí como específico el selector es Esta es una buena suposición, pero no es una regla completamente confiable y causa algunos problemas:

  • Combina la acción de selección de elementoscon el acto de priorización de conjuntos de reglas.
  • La forma más sencilla de «arreglar» un conflicto con la especificidad es escalar el problema agregando selectores que de otro modo serían innecesarios o lanzando (sofocantes) !important Granada de mano.
.overly#powerful .framework.widget {
  color: maroon;
}

.my-single_class { /* add some IDs to this ??? */
  color: rebeccapurple; /* add !important ??? */
}

Solución: las capas en cascada proporcionan control

Capas en cascada dar a los autores de CSS un control más directo sobre la cascada para que podamos construir sistemas en cascada más deliberadamente sin depender tanto de suposiciones heurísticas relacionadas con la selección.

Utilizando @layer correctamente y en capas @imports, podemos establecer nuestro propio capas en cascada – Cree desde estilos de baja prioridad, como el restablecimiento y la configuración predeterminada, a través de temas, marcos y sistemas de diseño, hasta estilos de alta prioridad, como componentes, utilidades y reemplazos. La especificidad todavía se aplica a los conflictos en cada capapero los conflictos de capas siempre se resuelven utilizando estilos de capa de mayor prioridad.

@layer framework {
  .overly#powerful .framework.widget {
    color: maroon;
  }
}

@layer site {
  .my-single_class {
    color: rebeccapurple;
  }
}

Estas capas están dispuestas y agrupadas de modo que no aumentan de la misma manera que lo hacen la especificidad y la importancia. Las capas en cascada no son acumulativas como los selectores. Agregar más capas no hagas nada más importanteTampoco son binarios en importancia, saltando repentinamente a la parte superior de la pila, o numerados como z-indexdonde tenemos que adivinar un número grande (z-index: 9999999?). De hecho, los estilos predeterminados son de varias capas. sin importancia que los estilos en capas.

@layer defaults {
  a:any-link { color: maroon; }
}

/* un-layered styles have the highest priority */
a {
  color: mediumvioletred;
}

¿Dónde encajan las capas en la cascada?

La cascada es una serie de pasos (algoritmo) para resolver conflictos entre estilos.

html { --button: teal; }
button { background: rebeccapurple !important; }
.warning { background: maroon; }
<button class="warning" style="background: var(--button);">
  what color background?
</button>

Con la adición de capas en cascada, estos pasos son:

Especificidad del selector es solo una pequeña parte de la cascada, pero también es el paso con el que más interactuamos, y a menudo se usa para denotar de manera más general el conjunto prioridad en cascadala gente puede decir eso !important bandera o style Atributo «agrega especificidad»: una forma rápida de expresar ese estilo se está convirtiendo en una prioridad más alta en la cascada. Dado que las capas en cascada se agregan directamente sobre la especificidad, tiene sentido pensar en ellas de manera similar: un paso más poderoso que los selectores de ID.

Sin embargo, las capas en cascada de CSS también hacen que sea más importante comprender completamente el papel de !important en cascada, no solo como una herramienta para «aumentar la especificidad», sino como un sistema para equilibrar los miedos.

!important ¡el origen, el contexto y las capas están invertidos!

Como autores web, a menudo pensamos en !important como una forma de aumentar la especificidad, cancelar estilos integrados o selectores muy específicos. Esto funciona bien en la mayoría de los casos (si está de acuerdo con la escalada), pero pierde el objetivo principal de importancia como una característica en la cascada general.

La importancia no es solo aumentar el poder, sino equilibrar el poder entre diferentes preocupaciones en competencia.

Origen importante

Todo comienza con origende donde proviene el estilo en el ecosistema web. Hay tres orígenes principales en CSS:

  • EN navegador (o agente del consumidor)
  • EN usuario (a menudo a través de las preferencias del navegador)
  • web autores (¡Somos nosotros!)

Los navegadores proporcionan valores predeterminados legibles para todos los elementos y luego los usuarios establecen sus preferencias, y luego nosotros (los autores) proporcionamos el diseño previsto para nuestras páginas web. Por lo tanto, los navegadores predeterminados tienen la prioridad más baja, las preferencias del usuario anulan la configuración predeterminada del navegador y podemos reemplazar cada uno.

Pero los creadores de CSS fueron muy claros en que realmente no deberíamos tener la última palabra:

Si surgen conflictos el usuario debe tener la última palabrapero también se debe permitir que el autor adjunte consejos de estilo.

– Håkon Lie (énfasis añadido)

importancia proporciona una forma para que el navegador y los usuarios vuelvan a establecer su prioridad cuando más importa !important la bandera se agrega al estilo, se crean tres nuevas capas y se invierte el orden.

  1. !important Estilos de navegador (más poderosos)
  2. !important preferencias del consumidor
  3. !important estilos autorales
  4. estilos de autor normales
  5. preferencias normales del consumidor
  6. estilos de navegador normales (menos potentes)

Para nosotros, agregar !important no cambia mucho (nuestros estilos importantes están bastante cerca de nuestros estilos normales), pero para el navegador y el usuario es una herramienta muy poderosa para recuperar el control. Las hojas de estilo predeterminadas del navegador incluyen una serie de estilos importantes que nos sería imposible deshacer, como:

iframe:fullscreen {
  /* iframes in full-screen mode don't show a border. */
  border: none !important;
  padding: unset !important;
}

Aunque los navegadores más populares dificultan la carga de hojas de estilo personalizadas reales, todos ofrecen preferencias de usuario: una interfaz gráfica para establecer estilos de usuario específicos. Siempre hay una casilla de verificación disponible en esta interfaz para que los usuarios elijan si un sitio puede o no anular sus preferencias. Esto es lo mismo que el ajuste !important en la hoja de estilo del usuario:

Captura de pantalla de las preferencias de fuente del usuario.

Contexto importante

La misma lógica básica se aplica a contexto en la cascada De forma predeterminada, los estilos del documento principal (DOM ligero) reemplazan los estilos de contexto integrados (DOM ligero). La adición, sin embargo !important invierte el orden:

  1. !important contexto de sombra (más poderoso)
  2. !important contexto anfitrión
  3. contexto de anfitrión normal
  4. contexto de sombra normal (menos poderoso)

Los estilos importantes que provienen del contexto de la sombra reemplazan los estilos importantes definidos por el documento principal. Aquí hay uno odd-bird elemento personalizado con algunos estilos escritos en la plantilla de sombra (DOM de sombra) y algunos estilos en la hoja de estilo de la página host (DOM de luz):

Ambas cosas color Las declaraciones tienen un significado normal, al igual que la página de host. mediumvioletred tiene prioridad pero font-family las declaraciones están marcadas !importantdando preferencia al contexto de sombra donde fantasy se define.

Capas importantes

Las capas en cascada funcionan de la misma manera que el origen y el contexto, con las capas importantes en orden inverso. La única diferencia es que las capas hacen que este comportamiento sea mucho más notorio.

Una vez que comencemos a usar capas en cascada, tendremos que ser mucho más cuidadosos y reflexivos sobre la forma en que usamos !important. Esta ya no es una forma rápida de saltar a la cima de las prioridades: es una parte integrada de nuestra estratificación en cascada; camino para que las capas inferiores insistir que algunos de sus estilos son imprescindibles.

Debido a que las capas en cascada se personalizan, no hay un orden predefinido. Pero podemos imaginarnos comenzando con tres capas:

  1. utilidades (más poderosas)
  2. componentes
  3. configuración predeterminada (menos potente)

Cuando los estilos en estas capas se marcan como importantes, generarán tres nuevas capas importantes invertidas:

  1. !important configuración predeterminada (más potente)
  2. !important componentes
  3. !important utilidades
  4. utilidades normales
  5. componentes normales
  6. configuración predeterminada normal (menos potente)

En este ejemplo, el color está determinado por las tres capas normales y por utilities capa gana el conflicto aplicando maroon color, como utilities capa tiene una prioridad más alta en @layersPero fíjate que text-decoration la propiedad esta marcada !important en ambos defaults y components capas donde esta importante defaults prevalecen, aplicando el subrayado declarado por defaults:

Establecer el orden de las capas.

Podemos crear cualquier cantidad de capas y nombrarlas o agruparlas de diferentes maneras, pero lo más importante que debemos hacer es asegurarnos de que nuestras capas se apliquen en el orden correcto de prioridad.

Una capa se puede usar repetidamente a lo largo de la base del código: las capas en cascada se organizan en el orden en que se colocan. aparecer primero. La primera capa encontrada está en la parte inferior (menos poderosa) y la última capa está en la parte superior (más poderosa). Pero luego, por encima de eso, los estilos sin capas tienen la prioridad más alta:

@layer layer-1 { a { color: red; } }
@layer layer-2 { a { color: orange; } }
@layer layer-3 { a { color: yellow; } }
/* un-layered */ a { color: green; }
  1. estilos en capas (más poderosos)
  2. capa-3
  3. capa-2
  4. capa-1 (menos potente)

Luego, como se discutió anteriormente, todos los estilos importantes se aplican en orden inverso:

@layer layer-1 { a { color: red !important; } }
@layer layer-2 { a { color: orange !important; } }
@layer layer-3 { a { color: yellow !important; } }
/* un-layered */ a { color: green !important; }
  1. !important capa-1 (más potente)
  2. !important capa-2
  3. !important capa-3
  4. !important estilos sin capas
  5. estilos normales sin capas
  6. capa normal-3
  7. capa normal-2
  8. capa normal-1 (menos potente)

Las capas también se pueden agrupar, lo que nos permite hacer una ordenación más compleja en el nivel más alto y capas anidadas:

@layer layer-1 { a { color: red; } }
@layer layer-2 { a { color: orange; } }
@layer layer-3 {
  @layer sub-layer-1 { a { color: yellow; } }
  @layer sub-layer-2 { a { color: green; } }
  /* un-nested */ a { color: blue; }
}
/* un-layered */ a { color: indigo; }
  1. estilos en capas (más poderosos)
  2. capa-3
    1. la capa 3 no está anidada
    2. capa-3 subcapa-2
    3. capa-3 subcapa-1
  3. capa-2
  4. capa-1 (menos potente)

Las capas agrupadas siempre permanecen juntas al final de las capas (por ejemplo, las subcapas de la capa 3 estarán todas una al lado de la otra), pero por lo demás se comporta de la misma manera que si la lista estuviera «aplanada», girándola en una lista de seis elementos. Al revés !important el orden de las capas, toda la lista está alineada.

Pero las capas no tienen que definirse en un solo lugar. Les damos nombres para que las capas se puedan definir en un solo lugar (para determinar el orden de las capas), y luego podemos agregarles estilos desde cualquier lugar:

/* describe the layer in one place */
@layer my-layer;

/* append styles to it from anywhere */
@layer my-layer { a { color: red; } }

Incluso podemos definir una lista ordenada completa de capas en una declaración:

@layer one, two, three, four, five, etc;

Esto permite que el autor de un sitio tenga la última palabra sobre el orden de las capas. Al proporcionar el orden de las capas por adelantado antes de que se importe un código de terceros, el orden se puede establecer y reorganizar en un solo lugar sin preocuparse por cómo se usan las capas en cada herramienta de terceros.

Sintaxis: trabajar con capas en cascada

¡Veamos la sintaxis!

Ordenando @layer declaraciones

Dado que las capas están dispuestas en el orden en que están definidas, ¡es importante tener una herramienta para establecer este orden en un solo lugar!

nosotros podemos usar @layer operadores para esto. La sintaxis es:

@layer <layer-name>#;

este hachís (#) significa que podemos agregar tantos nombres de capas como queramos a una lista separada por comas:

@layer reset, defaults, framework, components, utilities;

Esto establecerá el orden de las capas:

  1. estilos en capas (más poderosos)
  2. utilidades
  3. componentes
  4. marco
  5. por defecto
  6. reinicio (menos potente)

Podemos hacer esto tantas veces como queramos, pero recuerda: lo importante es el orden de cada nombre aparece primeroAsí que esto tendrá el mismo resultado:

@layer reset, defaults, framework;
@layer components, defaults, framework, reset, utilities;

La lógica de apilamiento ignorará el orden de reset, defaultsy framework en el segundo @layer regla porque estas capas ya están establecidas @layer La sintaxis de la lista no agrega ninguna magia especial a la lógica de organizar las capas: las capas se organizan en función de el orden en que las capas aparecen por primera vez en su código.Luego, reset aparece primero en la primera @layer lista. Todos los tipos @layer una declaración que viene más tarde solo puede agregar nombres de capa a la lista, pero no puede mover capas existentesEsto garantiza que siempre pueda controlar el orden general final de las capas desde un solo lugar, al comienzo de sus estilos.

Estas expresiones de capas están permitidas en la parte superior de la hoja de estilo antes @import regla (pero no entre los importados). Le recomendamos encarecidamente que utilice esta función para configurar todas sus capas por adelantado en un solo lugar para que siempre sepa dónde buscar o hacer cambios.

Bloqueo @layer normas

La versión en bloque de @layer la regla acepta solo un nombre de capa, pero luego le permite agregar estilos a esa capa:

@layer <layer-name> {
  /* styles added to the layer */
}

Puedes poner la mayoría de las cosas dentro @layer bloque: solicitudes de medios, selectores y estilos, solicitudes de soporte, etc. Las únicas cosas que no puede poner en un bloque de capa son cosas como conjuntos de caracteres, importaciones y espacios de nombres. Pero no se preocupe, hay una sintaxis para importar estilos en una capa.

Si el nombre de la capa no se ha establecido antes, esta regla de capa lo agregará al orden de las capas. Pero si se establece el nombre, le permite agregar estilos a las capas existentes desde cualquier parte del documento, sin cambiar la prioridad de cada capa.

Si hemos establecido nuestro orden de capas de antemano con la regla de expresión de capas, ya no tenemos que preocuparnos por el orden de estos bloques. capa:

/* establish the order up-front */
@layer defaults, components, utilities;

/* add styles to layers in any order */
@layer utilities {
  [hidden] { display: none; }
}

/* utilities will override defaults, based on established order */
@layer defaults {
  * { box-sizing: border-box; }
  img { display: block; }
}

Agrupación de capas (anidadas)

Las capas se pueden agrupar por reglas de capas anidadas:

@layer one {
  /* sorting the sub-layers */
  @layer two, three;

  /* styles ... */
  @layer three { /* styles ... */ }
  @layer two { /* styles ... */ }
}

Esto genera capas agrupadas que se pueden representar asociando nombres de padre e hijo con un punto. Esto significa que se puede acceder a las subcapas resultantes directamente fuera del grupo:

/* sorting nested layers directly */
@layer one.two, one.three;

/* adding to nested layers directly */
@layer one.three { /* ... */ }
@layer one.two { /* ... */ }

Las reglas para organizar las capas se aplican en cada nivel de aplicación. Todos los estilos que no están extra anidados se consideran «sin capas» en este contexto y tienen prioridad sobre otros estilos anidados:

@layer defaults {
  /* un-layered defaults (higher priority) */
  :any-link { color: rebeccapurple; }

  /* layered defaults (lower priority) */
  @layer reset {
    a[href] { color: blue; }
  }
}

Las capas agrupadas también están contenidas en su padre para que el orden de las capas no se mezcle entre los grupos. En este ejemplo, las capas de nivel superior se ordenan primero y luego las capas se ordenan en cada grupo:

@layer reset.type, default.type, reset.media, default.media;

El resultado es una serie de capas de:

  • sin capas (la más poderosa)
  • grupo predeterminado
    • por defecto sin capas
    • default.media
    • predeterminado.tipo
  • restablecer grupo
    • Reiniciar sin capas
    • reset.media
    • restablecer.tipo

Tenga en cuenta que los nombres de capa también tienen un alcance para que no interactúen ni entren en conflicto con capas con un nombre similar fuera de su contexto anidado. Ambos grupos pueden tener diferentes media subcapas.

Esta agrupación se vuelve especialmente importante cuando se usa @import o <link> para superponer hojas de estilo completas. Instrumento de terceros, p. Orejapodemos usar capas internamente, pero podemos incrustar estas capas en compartido bootstrap agrupe las capas al importar para evitar posibles conflictos de nombres de capas.

Superponga hojas de estilo completas con @import o <link>

Se pueden agregar hojas de estilo completas a una capa usando nuevas layer() sintaxis de funciones con @import normas:

/* styles imported into to the <layer-name> layer */
@import url("https://css-tricks.com/css-cascade-layers/example.css") layer(<layer-name>);

También hay una sugerencia para agregar un layer atributo en HTML <link> elemento – aunque esto todavía está en desarrollo y aún no se mantiene en ninguna parteEsto se puede usar para importar herramientas de terceros o bibliotecas de componentes mientras se agrupan todas las capas internas bajo un nombre de capa, o como una forma de organizar las capas en archivos separados.

Capas anónimas (sin nombre)

Nombres de capas son útiles porque nos permiten acceder a la misma capa desde varios lugares para ordenar o combinar bloques de capas, pero no son obligatorios.

Es posible crear anónimo (sin nombre) capas usando la regla de capa de bloque:

@layer { /* ... */ }
@layer { /* ... */ }

O usando la sintaxis para importar, con un layer palabra clave en lugar de layer() función:

/* styles imported into to a new anonymous layer */
@import url('../example.css') layer;

Cada capa anónima es única y se agrega al orden de las capas donde ocurre. Las capas anónimas no se pueden reenviar mediante otras reglas de capas para ordenar o agregar más estilos.

Probablemente necesiten usarse con moderación, pero puede haber varios usos:

  • Los proyectos pueden garantizar que todos los estilos de una capa deban estar ubicados en un solo lugar.
  • Las herramientas de terceros pueden «ocultar» sus capas internas en capas anónimas para que no se conviertan en parte de la API pública de la herramienta.

Devolver valores a la capa anterior

Hay varias formas que podemos usar para «hacer retroceder» un estilo en cascada a un valor anterior definido por un origen o capa de menor prioridad. Esto incluye una serie de valores CSS globales existentes y uno nuevo revert-layer una palabra clave que también será global (funciona en cada propiedad).

Contexto: palabras clave en cascada globales existentes *

CSS tiene varios palabras clave globales que se puede utilizar para cualquier propiedad para ayudar a devolver la cascada de diferentes maneras.

  • initial establece la propiedad de especificar valor antes de que se aplique cualquier estilo (incluida la configuración predeterminada del navegador). Esto puede ser una sorpresa, ya que a menudo pensamos en los estilos de navegador como valores predeterminados, pero por ejemplo initial valor de display es inlineno importa en qué elemento lo usemos.
  • inherit establece la propiedad para aplicar un valor del elemento principal. Este es el valor predeterminado para las propiedades heredadas, pero aún se puede usar para eliminar un valor anterior.
  • unset actúa como si simplemente eliminara todos los valores anteriores, por lo que las propiedades heredadas nuevamente inheritmientras que las propiedades heredadas vuelven a ser propias initial valor.
  • revert elimina solo los valores que hemos aplicado al origen del autor (es decir, estilos del sitio). Esto es lo que queremos en la mayoría de los casos, ya que permite que el navegador y los estilos personalizados permanezcan intactos.
Nuevo: revert-layer palabra clave

Las capas en cascada agregan un nuevo global revert-layer palabra clave. Funciona de la misma manera que revertpero solo elimina los valores que aplicamos a la capa de cascada actual. Podemos usarlo para invertir la cascada y usar el valor que se definió en las capas anteriores.

En este ejemplo, no-theme clase elimina todos los valores establecidos en theme capa.

@layer default {
  a { color: maroon; }
}

@layer theme {
  a { color: var(--brand-primary, purple); }

  .no-theme {
    color: revert-layer;
  }
}

Así que la etiqueta de contacto .no-theme la clase volverá a usar el valor establecido en default capa.Cuando revert-layer utilizado en estilos sin capas, se comporta de la misma manera que revert – volver al origen anterior.

Devolver capas importantes

Las cosas se ponen interesantes si sumamos !important para revert-layer palabra clave. Porque cada capa tiene dos «normales» e «importantes» separados posiciones en la cascadano solo cambia la prioridad de la declaración, sino que cambia qué capas se devuelven.

Supongamos que tenemos tres capas definidas en una pila de capas que se ve así:

  1. utilidades (más poderosas)
  2. componentes
  3. configuración predeterminada (menos potente)

Podemos agregar esto para incluir no solo posiciones normales e importantes en cada capa, sino también estilos sin capas y animaciones:

  1. !important configuración predeterminada (más potente)
  2. !important componentes
  3. !important utilidades
  4. !important estilos sin capas
  5. animaciones CSS
  6. estilos normales sin capas
  7. utilidades normales
  8. componentes normales
  9. configuración predeterminada normal (menos potente)

Ahora que usamos revert-layer en capa normal (vamos a usar utilities) el resultado es bastante directo. Estamos regresando solo esta capamientras que todo lo demás se aplica normalmente:

  1. !important configuración predeterminada (más potente)
  2. !important componentes
  3. !important utilidades
  4. !important estilos sin capas
  5. ✅ animaciones CSS
  6. ✅ estilos normales sin capas
  7. ❌ servicios públicos normales
  8. ✅ componentes normales
  9. ✅ configuración predeterminada normal (menos potente)

Pero cuando movemos eso revert-layer en una posición importante, devolvemos tanto la versión normal como la importante junto con todo lo demás:

  1. !important configuración predeterminada (más potente)
  2. !important componentes
  3. !important utilidades
  4. !important estilos sin capas
  5. ❌ animaciones CSS
  6. ❌ estilos normales sin capas
  7. ❌ servicios públicos normales
  8. ✅ componentes normales
  9. ✅ configuración predeterminada normal (menos potente)

Casos de uso: ¿Cuándo me gustaría usar capas en cascada?

Entonces, ¿en qué situaciones podemos encontrarnos usando capas en cascada? Estos son algunos ejemplos de cuándo las capas en cascada tienen mucho sentido, así como otros en los que No Tiene mucho sentido.

Restablecimientos menos intrusivos y configuraciones predeterminadas

Uno de los casos más claros de uso inicial sería hacer ajustes por defecto con baja prioridad que son fáciles de deshacer.

Algunos reinicios ya hacen esto aplicando :where() pseudoclase alrededor de cada selector. :where() elimina todos los detalles de los selectores a los que se aplica, lo que tiene el impacto principal deseado, pero también algunas desventajas:

  • Debe aplicarse a cada selector individualmente
  • Los conflictos de reinicio deben resolverse sin especificidad

Las capas nos permiten envolver más fácilmente toda la tabla con estilos de reinicio, o con la ayuda del bloque. @layer regla:

/* reset.css */
@layer reset {
  /* all reset styles in here */
}

O al importar un reinicio:

/* reset.css */
@import url(reset.css) layer(reset);

¡O ambos! Las capas se pueden anidar sin cambiar su prioridad. De esta manera, puede usar el restablecimiento de terceros y asegurarse de que se agregue a la capa que desea, ya sea que la hoja de estilo de restablecimiento en sí esté escrita o no usando capas internamente.

Debido a que los estilos multicapa tienen una prioridad más baja que los estilos «sin capa» de manera predeterminada, esta es una buena manera de comenzar a usar capas en cascada sin tener que volver a escribir toda la base de código CSS.

Los selectores de restablecimiento aún tienen información específica para ayudar a resolver conflictos internos sin envolver cada selector individual, pero también obtiene el resultado deseado de restablecer una hoja de estilo que es fácil de deshacer.

Administre una arquitectura CSS compleja

A medida que los proyectos se vuelven más grandes y complejos, puede ser útil definir límites más claros para nombrar y organizar el código CSS. Pero cuanto más CSS tenemos, más potencial tenemos para los conflictos, especialmente de diferentes partes de un sistema como un «tema» o una «biblioteca de componentes» o un conjunto de «clases útiles».

No solo queremos que estén organizados por función, sino que también puede ser útil organizarlos en función de qué partes del sistema tienen prioridad en caso de conflicto. CSS triángulo invertido de Harry Robert hace un buen trabajo al visualizar lo que estas capas podrían contener.

De hecho, el paso inicial de agregar capas a la cascada de CSS utiliza la metodología ITCSS como ejemplo básico y guía para desarrollar la característica.

No se requiere ninguna técnica especial, pero probablemente sea útil limitar los proyectos a un conjunto predefinido de capas de nivel superior y luego expandir ese conjunto con capas anidadas según corresponda.

Por ejemplo:

  1. reinicio de bajo nivel y estilos de normalización
  2. elementos predeterminadospara tipografía básica y legibilidad
  3. temascomo modos claro y oscuro
  4. plantillas reutilizables que puede ocurrir en múltiples componentes
  5. diseño y estructuras de página más grandes
  6. individual componentes
  7. cancela y utilidades

Podemos crear esta pila de capas de nivel superior al comienzo de nuestro CSS, con una declaración de una sola capa:

@layer
  reset,
  default,
  themes,
  patterns,
  layouts,
  components,
  utilities;

Las capas exactas que necesita y la forma en que las nombra pueden cambiar de un proyecto a otro.

A partir de ahí, creamos desgloses de capas aún más detallados. Tal vez nuestros propios componentes tengan configuraciones, estructuras, temas y utilidades internas predeterminadas.

@layer components {
  @layer defaults, structures, themes, utilities;
}

Sin cambiar la estructura de nivel superior, ahora tenemos una forma de superponer los estilos en cada componente.

Uso de herramientas y marcos de terceros

La integración de CSS de terceros con un proyecto es uno de los lugares más comunes para los problemas en cascada. Ya sea que usemos un restablecimiento compartido como Normalizer o CSS Remedy, un sistema de diseño común como Material Design, un marco como Bootstrap o una herramienta auxiliar como Tailwind, no siempre podemos controlar la especificidad o la importancia del selector de todos los CSS utilizados en nuestros sitios. . A veces, esto incluso se extiende a bibliotecas internas, sistemas de diseño y herramientas administradas en otras partes de una organización.

Como resultado, a menudo tenemos que estructurar nuestro CSS interno en torno a un código de terceros o escalar los conflictos cuando surgen, con una especificidad artificialmente alta o !important Luego debemos mantener estos trucos a lo largo del tiempo, adaptándonos a los cambios en la cadena.

Las capas en cascada nos brindan una forma de insertar código de terceros en la cascada de cada proyecto exactamente donde queremos que viva, sin importar cómo se escriban internamente los selectores. Dependiendo del tipo de biblioteca que utilicemos, podemos hacer esto de diferentes maneras. Comencemos con una pila de capas básica, pasando de reinicio a utilidades:

@layer reset, type, theme, components, utilities;

Y luego podemos incluir algunas herramientas…

Usar reinicio

Si usamos una herramienta como CSS Remedy, es posible que también tengamos algunos estilos de reinicio personalizados que queramos incluir. Importemos CSS Remedy en la subcapa en reset:

@import url('remedy.css') layer(reset.remedy);

Ahora podemos agregar nuestros propios estilos de reinicio a reset capa, sin entrada adicional (a menos que lo queramos). Porque los estilos directamente en reset deshará todos los estilos anidados adicionales, podemos estar seguros de que nuestros estilos siempre tendrán prioridad sobre CSS Remedy si hay un conflicto, sin importar los cambios en la nueva versión:

@import url('remedy.css') layer(reset.remedy);

@layer reset {
  :is(ol, ul)[role="list"] {
    list-style: none;
    padding-inline-start: 0;
  }
}

Y desde reset capa está en la parte inferior de la pila, el resto del CSS en nuestro sistema anulará tanto Remedy como nuestros propios complementos de reinicio local.

Uso de clases útiles.

En el otro extremo de nuestra pila, las «clases útiles» en CSS pueden ser una forma útil de reproducir patrones comunes (como un contexto adicional para lectores de pantalla) de una manera ampliamente aplicable. Las utilidades tienden a romper la heurística de la especificidad porque queremos que se definan de manera amplia (lo que conduce a una baja especificidad), pero también queremos que «ganen» los conflictos.

Como tienes un utilities capa en la parte superior de nuestra pila de capas, podemos hacerlo posible. Podemos usar esto de manera similar al ejemplo de reinicio, mientras cargamos utilidades externas en una subcapa y proporcionamos las nuestras:

@import url('tailwind.css') layer(utilities.tailwind);

@layer utilities {
  /* from https://kittygiraudel.com/snippets/sr-only-class/ */
  /* but with !important removed from the properties */
  .sr-only {
    border: 0;
    clip: rect(1px, 1px, 1px, 1px);
    -webkit-clip-path: inset(50%);
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    margin: -1px;
    padding: 0;
    position: absolute;
    width: 1px;
    white-space: nowrap;
  }
}
Uso de sistemas de diseño y bibliotecas de componentes.

Hay muchas herramientas CSS que se encuentran en algún lugar en el medio de nuestra pila de capas, que combinan configuraciones tipográficas predeterminadas, temas, componentes y otros aspectos del sistema.

Dependiendo de la herramienta específica, podemos hacer algo similar a los ejemplos de reinicio y ayuda anteriores, pero hay algunas otras opciones. Una herramienta altamente integrada puede merecer una capa de nivel superior:

@layer reset, bootstrap, utilities;
@import url("https://css-tricks.com/css-cascade-layers/bootstrap.css") layer(bootstrap);

Si estas herramientas comienzan a proporcionar capas como parte de su API pública, también podríamos dividirla en partes, lo que nos permitiría dispersar nuestro código con la biblioteca:

@import url('bootstrap/reset.css') layer(reset.bootstrap);
@import url('bootstrap/theme.css') layer(theme.bootstrap);
@import url('bootstrap/components.css') layer(components.bootstrap);

@layer theme.local {
  /* styles here will override theme.bootstrap */
  /* but not interfere with styles from components.bootstrap */
}

Uso de capas con marcos existentes (¡sin capas,! Importante, completo)

Al igual que con cualquier cambio de idioma importante, habrá un período de ajuste cuando las capas en cascada de CSS se generalicen. ¿Qué sucede si su equipo está listo para comenzar a usar capas el próximo mes, pero su marco favorito decide esperar otros tres años antes de cambiar a estilos de varias capas? Probablemente todavía se usarán muchos marcos !important más a menudo de lo que nos gustaría! !important capas invertidas, esto no es ideal.

Sin embargo, las capas aún pueden ayudarnos a resolver el problema. Sólo tenemos que ser inteligentes al respecto. Decidimos qué capas queremos para nuestro proyecto y eso significa que podemos agregar capas arriba y también debajo de las capas del marco que creamos.

Por ahora, sin embargo, podemos usar una capa de deshacer inferior !important estilos de marco y una capa superior para anular los estilos normales. Algo como esto:

@layer framework.important, framework.bootstrap, framework.local;
@import url("https://css-tricks.com/css-cascade-layers/bootstrap.css") layer(framework.bootstrap);

@layer framework.local {
  /* most of our normal framework overrides can live here */
}

@layer framework.important {
  /* add !important styles in a lower layer */
  /* to override any !important framework styles */
}

Todavía parece un truco, pero nos ayuda a avanzar en la dirección correcta: hacia una cascada más estructurada. Esperamos que esta sea una solución temporal.

Diseñar una herramienta o marco CSS

Para cualquiera que admita la biblioteca CSS, las capas en cascada pueden ayudar con la organización interna e incluso convertirse en parte de la API del desarrollador. Al nombrar las capas internas de una biblioteca, podemos permitir que los usuarios de nuestro marco se asocien con esas capas al personalizar o reemplazar los estilos que proporcionamos.

Por ejemplo, Bootstrap puede exponer capas para sus «reinicios», «redes» y «utilidades», probablemente dispuestas en ese orden. Ahora el usuario puede decidir si quiere cargar estas capas de Bootstrap en diferentes capas locales:

@import url(bootstrap/reboot.css) layer(reset); /* reboot » reset.reboot */
@import url(bootstrap/grid.css) layer(layout); /* grid » layout.grid */
@import url(bootstrap/utils.css) layer(override); /* utils » override.utils */

O el usuario puede cargarlos en una capa Bootstrap, con capas locales dispersas:

@layer bs.reboot, bs.grid, bs.grid-overrides, bs.utils, bs.util-overrides;
@import url('bootstrap-all.css') layer(bs);

También es posible ocultar las capas internas a los usuarios cuando lo desee agrupando las capas internas/privadas en una capa anónima (sin nombre). Las capas anónimas se agregarán al orden de las capas donde ocurren, pero no estarán expuestas a que los usuarios las reorganicen o agreguen estilos.

Solo quiero que esta propiedad sea más !important

Contrariamente a algunas expectativas, las capas no facilitan la escalada rápida de un estilo particular para anular otro.

Si la mayoría de nuestros estilos no son capas, entonces cada nueva capa será despriorizado Podríamos hacer esto con bloques de estilo separados, pero rápidamente se volverá difícil de rastrear.

Las capas están diseñadas para ser más fundamentales, no estilo por estilo, sino para crear patrones consistentes a lo largo del proyecto. Idealmente, si lo configuramos correctamente, obtenemos el resultado correcto al mover nuestro estilo a la capa apropiada (y predefinida).

Si la mayoría de nuestros estilos ya se encuentran en capas bien definidas, siempre podemos considerar agregar una nueva capa con la mayor potencia en la parte superior de una pila, o usar estilos sin capas para reemplazar las capas. Incluso podemos pensar en debug capa en la parte superior de la pila para realizar trabajos de exploración fuera de la producción.

Pero agregar nuevas capas sobre la marcha puede destruir la utilidad organizativa de esta función y debe usarse con precaución. Lo mejor es preguntar: ¿Por qué este estilo debe anular al otro?

Si la respuesta está relacionada con una tipo de estilo siempre reemplazando otro tipo, las capas son probablemente la solución correcta. Esto puede deberse a que estamos reemplazando estilos que provienen de un lugar que no controlamos, o porque estamos escribiendo una utilidad y necesita moverse a nuestro utilities Si la respuesta está relacionada con estilos más específicos, reemplazando estilos menos específicos, podemos considerar hacer que los selectores reflejen esta especificidad.

O, en casos raros, incluso podemos tener estilos que realmente son importante – La función simplemente no funciona si reemplaza este estilo en particular. Podríamos decir agregando display: none para [hidden] el atributo pertenece a nuestro restablecimiento con la prioridad más baja, pero aun así debería ser difícil de deshacer. En este caso, !important es realmente la herramienta adecuada para el trabajo:

@layer reset {
  [hidden] { display: none !important; }
}

¿Estilos de alcance y entre nombres? ¡No!

Las capas en cascada son obviamente una herramienta organizativa y una que «captura» la influencia de los selectores, especialmente cuando están en conflicto. Por lo que puede resultar tentador a primera vista verlos como una solución para gestionar el rango o espacio entre nombres.

Un primer instinto común es crear una capa para cada componente del proyecto, con la esperanza de que esto asegure (por ejemplo) que .post-title se aplica sólo dentro de un .post.

Pero los conflictos en cascada no son lo mismo que los conflictos de nombres, y las capas no están muy bien diseñadas para este tipo de organización con alcance. Las capas en cascada no restringen cómo los selectores coinciden o se aplican a HTML, sino solo cómo se conectan en cascada. Entonces, a menos que podamos estar seguros de que el componente X siempre reemplace el componente Y, las capas separadas de componentes no ayudarán mucho. Tendremos que mirar en su lugar sugirió @scope especial que se está desarrollando.

Puede ser útil pensar en las capas y los rangos de los componentes como problemas superpuestos:

Ilustración que muestra cómo se pueden organizar las capas en cascada de CSS por alcance, como botones, mapas y capas de entrada que se encuentran dentro de los rangos de componentes, temas y predeterminados.

Ámbitos describir Qué estilizamos mientras las capas describen por qué También podemos pensar en las capas como si representaran de donde viene el estilomientras que los rangos representan a qué se adjuntará el estilo.

Pon a prueba tus conocimientos: qué estilo ¿ganar?

Para cada situación, acepte este párrafo:

<p id="intro">Hello, World!</p>

Pregunta 1

@layer ultra-high-priority {
  #intro {
    color: red;
  }
}

p {
  color: green;
}

¿De qué color es el párrafo?

Aunque la capa tiene un nombre para ella suena bastante importantelos estilos en capas tienen una mayor prioridad en la cascada. Entonces el párrafo será green.

Pregunta 2

@layer ren, stimpy;

@layer ren {
  p { color: red !important; }
}

p { color: green; }

@layer stimpy {
  p { color: blue !important; }
}

¿De qué color es el párrafo?

Nuestro orden normal de capas se establece al principio: ren en la parte inferior, entonces stimpyluego (como siempre) estilos sin capas en la parte superior. Pero estos estilos no son todos normalalgunos de ellos son importantes. Solo podemos filtrar hasta inmediatamente !important estilos e ignorar lo que no es importante greenRecuerde que el «origen e importancia» es el primer paso en la cascada, incluso antes de que consideremos la estratificación.

Esto nos deja con dos estilos importantes, ambos en capas. A medida que nuestras capas importantes se invierten, ren se mueve hacia arriba y stimpy hasta el fondo. El párrafo será red.

Pregunta 3

@layer Montagues, Capulets, Verona;

@layer Montagues.Romeo { #intro { color: red; } }
@layer Montagues.Benvolio { p { color: orange; } }

@layer Capulets.Juliet { p { color: yellow; } }
@layer Verona { * { color: blue; } }
@layer Capulets.Tybalt { #intro { color: green; } }

¿De qué color es el párrafo?

Todos nuestros estilos tienen el mismo origen y contexto, ninguno está marcado como importante y ninguno de ellos es un estilo incorporado. Aquí tenemos una amplia gama de selectores, desde un identificador muy específico #intro a la especificidad cero universal * Pero las capas están permitidas antes de que tengamos en cuenta los detalles, por lo que por ahora podemos ignorar los selectores.

El orden de la capa primaria se establece al frente y luego las subcapas se agregan internamente. Pero las subcapas se clasifican junto con sus capas principales, lo que significa que todos Montagues tendrá la prioridad más baja, seguido de todos Capuletsy luego Verona hay una última palabra en el orden de las filas. Entonces podemos filtrar inmediatamente solo para Verona estilos que priman * el selector tiene cero especificidad, ganará.

¡Cuidado al colocar selectores universales en capas potentes!

Depurar conflictos de capas en las herramientas de desarrollo del navegador

Todos los navegadores Chrome, Safari, Firefox y Edge tienen herramientas para desarrolladores que le permiten verificar los estilos que se aplican a un elemento de la página. El panel de estilo de este inspector de elementos mostrará los selectores aplicados, ordenados por su prioridad en cascada (prioridad más alta en la parte superior) y luego los estilos heredados a continuación. Los estilos que no se aplican por alguna razón generalmente aparecerán atenuados o incluso tachados, a veces con información adicional sobre por qué El estilo no se aplica. Este es el primer lugar en el que debe buscar al depurar cualquier aspecto de la cascada, incluidos los conflictos de capas.

Safari Technology Preview y Firefox Nightly ya muestran (y ordenan) capas en cascada en este panel. Se espera que este conjunto de herramientas se utilice en versiones estables al mismo tiempo que las capas en cascada. La capa de cada selector se indica directamente encima del propio selector:

Chrome/Edge está trabajando en herramientas similares y se espera que esté disponible en las ediciones Canary (nocturnas) para cuando las capas en cascada lleguen a la versión estable. Haremos actualizaciones aquí a medida que estas herramientas cambien y mejoren.

Compatibilidad con navegador y copias de seguridad

Las capas en cascada están (o pronto estarán) disponibles de forma predeterminada en los tres mecanismos principales del navegador:

  • Cromo/borde 99+
  • Firefox 97+
  • Safari (actualmente en revisión)

Debido a que las capas están diseñadas para ser los componentes básicos de toda la arquitectura de CSS, es difícil imaginar la creación de reservas manuales de la misma manera que lo haría con otras características de CSS. Es probable que las funciones de copia de seguridad incluyan la duplicación de grandes fragmentos de código, con diferentes selectores de control de capas en cascada, o que proporcionen un estilo de copia de seguridad mucho más simple.

Soporte para la función de consulta a través de @supports

Hay @supports una función en CSS que permitirá a los autores probar el soporte en @layer y otras reglas:

@supports at-rule(@layer) {
  /* code applied for browsers with layer support */
}

@supports not at-rule(@layer) {
  /* fallback applied for browsers without layer support */
}

Sin embargo, tampoco está claro cuándo se mantendrá esta solicitud en los navegadores.

Establecer capas en HTML con <link> etiqueta

Todavía no existe una especificación de sintaxis oficial para superponer hojas de estilo html completas <link> etiqueta, pero hay una la propuesta esta en desarrolloEsta propuesta incluye una nueva layer atributo que se puede utilizar para asignar estilos a una capa nombrada o anónima:

<!-- styles imported into to the <layer-name> layer -->
<link rel="stylesheet" href="https://css-tricks.com/css-cascade-layers/example.css" layer="<layer-name>">

<!-- styles imported into to a new anonymous layer -->
<link rel="stylesheet" href="https://css-tricks.com/css-cascade-layers/example.css" layer>

Sin embargo, los navegadores antiguos sin soporte para layer el atributo lo ignorará por completo y continuará cargando la hoja de estilo sin capas. Los resultados pueden ser bastante inesperados. Por lo que la propuesta también amplía la existente media atributo para permitir solicitudes de soporte de función en un support() función.

Esto nos permitiría hacer que las conexiones multicapa sean condicionales, en función del soporte de capas:

<link rel="stylesheet" layer="bootstrap" media="supports(at-rule(@layer))" href="https://css-tricks.com/css-cascade-layers/bootstrap.css">

Posibles polifilos y soluciones alternativas

Los principales navegadores han cambiado a un modelo «siempre verde» con actualizaciones enviadas a los usuarios para un ciclo de lanzamiento relativamente corto. Incluso Safari lanza regularmente nuevas funciones en actualizaciones «parcheadas» entre sus versiones principales de aspecto más raro.

Eso significa que podemos esperar soporte del navegador para estas características para aumentar muy rápidamente. Para muchos de nosotros, puede ser conveniente comenzar a usar capas en solo unos meses sin preocuparnos demasiado por los navegadores antiguos.

Para otros, puede llevar más tiempo sentirse cómodos con el soporte de su propio navegador. Hay muchas otras formas de controlar la cascada, utilizando selectores, propiedades personalizadas y otras herramientas. También es teóricamente posible imitar (o reponer) el comportamiento básico. Hay gente que está trabajando en este polifílico, pero no está claro cuándo estará listo.

Más recursos

CSS Cascade Layers todavía está evolucionando, pero ya hay muchos recursos, que incluyen documentación, artículos, videos y demostraciones, para ayudarlo a obtener más información sobre las capas y cómo funcionan.

Ayuda

artículos

videoclips

Demostraciones

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba