Curso de CSS / organizar estilos: archivos, anidamiento y capas

El CSS mantenible separa valores compartidos, estilos base, componentes y ajustes condicionales según sus roles. El anidamiento nativo delimita selectores relacionados, mientras que las capas de cascada ordenan explícitamente grupos de reglas e introducen sus propias reglas de precedencia.

Reduce la duplicación y asigna responsabilidades a los archivos

Primero, busca duplicados del mismo color y espaciado, selectores obsoletos y reglas de botones casi idénticas. Los valores con el mismo rol se agrupan en variables, y los diferentes botones dividen reglas comunes y diferencias necesarias. Puede ser mejor mantener dos componentes independientes en lugar de crear condiciones complejas para eliminar toda duplicación. Al agrupar valores comunes, verifica el alcance y las condiciones de herencia de la variable en variables CSS: var(), alcance, herencia y valores de respaldo.

/* Before cleanup: Same value repeated in multiple places */
.lesson-button { padding: .65rem 1rem; color: #166b92; }
.notice-button { padding: .65rem 1rem; color: #166b92; }

/* After organizing: sharing common shapes and roles */
.button { padding: .65rem 1rem; color: var(--accent); }
.button.text-alert { color: #9d2632; }

La comparación anterior es un código parcial que explica la dirección de limpieza. También se debe adjuntar una clase de botón común al HTML real, y si solo renombras el CSS y dejas el HTML tal como está, la apariencia puede desaparecer. El ejercicio completo a continuación ejecuta esta configuración desglosada en archivos y capas.

archivo responsabilidad Juicio al revisar
tokens.css Colores y espacios comunes ¿Es un valor compartido por varios componentes?
base.css Fuente, margen por defecto, visualización de enfoque ¿Es este el comportamiento predeterminado para todo el documento?
layout.css Área de contenido y diseño ¿Es la relación posicional de los componentes?
components.css Forma y estado de tarjetas y botones ¿Está vinculado a un componente en particular?
utilities.css Clases auxiliares pequeñas y explícitas ¿Es esta una excepción que solo se aplicará en unos pocos lugares?

Para documentos pequeños, puede bastar con separar las secciones mediante comentarios dentro de un archivo. Considera separar archivos cuando varias personas modifiquen diferentes componentes o cuando aumente el alcance de la reutilización. El nombre del archivo es un separador para la navegación, y solo dividir el archivo no elimina los conflictos de selectores. También se deben gestionar las rutas de conexión HTML y las cascadas.

Distingue el elemento padre de sus descendientes al anidar

La anidación nativa de CSS es interpretada directamente por el navegador. Esto es diferente de la forma en que los preprocesadores como Sass generan CSS diferente durante la fase de compilación. El código a continuación coloca el título del .card cerca del estado de la propia tarjeta.

.card {
  & h2 { color: var(--accent); }
  &:hover { border-color: var(--accent); }
}

& h2 representa el h2 dentro de la tarjeta, y &:hover representa el hover de la propia tarjeta. Si insertas un espacio como & :hover, el resultado será diferente porque selecciona un descendiente sobre el que se hace hover. También distingue entre &.warning, que selecciona una clase auxiliar del mismo elemento, y & .warning, que selecciona descendientes.

/* The simple overlap above is expanded */
.card h2 { color: var(--accent); }
.card:hover { border-color: var(--accent); }

Con este selector de padre único, la anidación se puede comparar directamente con las reglas expandidas. Una lista de padres separada por comas puede hacer que la especificidad del selector anidado dependa del selector más específico en esa lista. Por lo tanto, la anidación compleja no es una concatenación de cadenas simple. Evita la profundidad innecesaria que vincula el CSS a una jerarquía HTML rígida. Para más detalles, consulta la guía de uso de anidación MDN, anidación y explicación de prioridad.

Verifica el soporte de anidación del navegador que necesitas soportar, y si necesitas un entorno que no lo soporte, elige CSS expandido como se indicó arriba o una herramienta de compilación apropiada. Solo porque uses una sintaxis nueva, no asumas que se aplica a todos tus visitantes.

Compara las capas de cascada antes que la especificidad

Para las declaraciones regulares del mismo estilo de autor, las declaraciones fuera de la capa tienen prioridad sobre las declaraciones dentro de la capa. Dentro de las capas, las capas posteriores tienen prioridad sobre las capas anteriores en un orden predeterminado. Así que las reglas de clase de una capa posterior pueden ganar a las reglas de ID de una anterior. Si otras condiciones de comparación como la misma capa e importancia son iguales, la especificidad y, después, la proximidad del ámbito y el orden de declaración deciden el resultado. Consulta herencia, especificidad y cascada de CSS .

@layer tokens, base, layout, components, utilities;
@layer base { #layer-target { color: #183044; } }
@layer utilities { .text-alert { color: #9d2632; } }

El botón de ejemplo coincide con ambos selectores. En la declaración general, las utilidades vienen después, por lo que se aplica el color rojo. Predecir el resultado solo porque un botón tiene una alta prioridad de ID puede ser incorrecto. El orden de las capas se determina por el orden en que se registran por primera vez sus nombres, y aunque abras la misma capa de nuevo más tarde, esa capa no se moverá al fondo.

Las declaraciones de !important tienen prioridad sobre las declaraciones generales, y el orden de capas para las declaraciones importantes está invertido. Entre declaraciones importantes del mismo origen, una capa anterior gana a una posterior y las declaraciones importantes con capa ganan a las que están fuera de ellas. Este ejemplo se limita a comparar capas de CSS del mismo autor y sus propiedades. No se expande a otras condiciones de la cascada, como estilos de usuario/navegador, declaraciones en línea y transiciones en ejecución, diciendo: “Solo necesitas mirar las capas.” Puedes consultar las condiciones completas en el documento de capas MDN.

Crea el HTML y cinco archivos CSS

Crea la estructura a continuación en una carpeta vacía. Todos los archivos se guardan como UTF-8. Dado que index.html usa la ruta relativa styles/..., el archivo CSS debe estar en la subcarpeta styles. Puedes abrir index.html con un navegador sin un servidor separado o biblioteca externa. Si no puedes leer el archivo, compara la ubicación del archivo y la dirección de conexión con aplicar CSS con estilos en línea, internos y externos.

stylesheet-project/
  index.html
  styles/
    tokens.css
    base.css
    layout.css
    components.css
    utilities.css

index.html contiene las etiquetas de enlace y clases actuales. El botón de comparación no es un botón para ejecutar una acción, sino que es para fines de práctica para verificar el color de texto aplicado y el foco.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>CSS files and layers by responsibility</title>
  <link rel="stylesheet" href="styles/tokens.css">
  <link rel="stylesheet" href="styles/base.css">
  <link rel="stylesheet" href="styles/layout.css">
  <link rel="stylesheet" href="styles/components.css">
  <link rel="stylesheet" href="styles/utilities.css">
</head>
<body>
  <main class="demo">
    <h1>Organizing a small stylesheet</h1>
    <article class="card">
      <h2>Scope nested rules to the card</h2>
      <p>The card heading uses the accent color. Compare it with the heading outside the card.</p>
      <button class="button" type="button">Regular button</button>
    </article>
    <section><h2>Heading outside the card</h2><p>Use the default font color.</p></section>
    <button id="layer-target" class="button text-alert" type="button">Layer comparison button</button>
  </main>
</body>
</html>

styles/tokens.css registra primero el orden de las capas y declara valores comunes. Otro archivo abre una capa con el mismo nombre para agregarle reglas.

@layer tokens, base, layout, components, utilities;
@layer tokens {
  :root { --ink: #183044; --accent: #166b92; --space-card: 1.25rem; }
}

styles/base.css establece la apariencia predeterminada del documento y el indicador de enfoque. Las reglas de ID son dispositivos establecidos para comparar el impacto de las capas en la prioridad.

@layer base {
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; padding: 1rem; color: var(--ink); font-family: sans-serif; line-height: 1.6; }
  h1 { font-size: 1.5rem; } h2 { font-size: 1.2rem; }
  button { font: inherit; cursor: pointer; }
  :focus-visible { outline: 3px solid #164f73; outline-offset: 3px; }
  #layer-target { color: #183044; }
}

styles/layout.css gestiona el espaciado entre áreas de contenido y secciones.

@layer layout {
  .demo { display: grid; gap: 1rem; max-width: 44rem; margin-inline: auto; }
  .demo > h1 { margin-block: 0 .5rem; }
  .demo > button { justify-self: start; }
}

styles/components.css gestiona tarjetas y botones. El color del título solo se aplica al interior de la tarjeta, y el borde cambia cuando pasas el cursor sobre la tarjeta o enfocas el botón dentro de ella.

@layer components {
  .card {
    padding: var(--space-card); border: 2px solid #90a4b2; border-radius: .5rem;
    & h2 { margin-top: 0; color: var(--accent); }
    &:hover, &:focus-within { border-color: var(--accent); }
  }
  .button {
    padding: .65rem 1rem; color: var(--accent); background: #eaf4fa;
    border: 1px solid #166b92; border-radius: .3rem;
  }
}

styles/utilities.css gestiona una clase auxiliar para el botón de comparar. Las declaraciones generales en este archivo tienen prioridad sobre las reglas de ID/botón en capas anteriores.

@layer utilities {
  .text-alert { color: #9d2632; }
}

Comprueba archivos, anidamiento y capas por separado

  1. En la pantalla principal, comprueba que el título de la tarjeta y el botón general sean azules, el título fuera de la tarjeta tenga el color predeterminado y el botón de comparación sea rojo. Usa Tab para ver si el botón tiene un indicador de enfoque.
  2. Comenta solo la regla & h2 dentro de la tarjeta en components.css. Los títulos de las tarjetas también vuelven a sus colores predeterminados. Después de la confirmación, descoméntala.
  3. Añade la clase text-alert a ambos botones en HTML. Los botones dentro de la tarjeta también serán rojos. Restaura solo las clases extra del botón interno eliminándolas.
  4. Al final de components.css, agrega solo .button { color: #28633b; } fuera del bloque @layer. Ambos botones se volverán verdes. Esto da como resultado declaraciones normales sin capa que ganan a las declaraciones normales de las capas. Después de la confirmación, elimina la nueva regla.
  5. Añade !important solo a la declaración de color del ID en base.css. El botón de comparación cambia al color predeterminado. En ese estado, si añades !important al color de utilities.css, se mantendrá el color básico de la capa anterior. Después de comparar, elimina ambos !important.
  6. Solo elimina temporalmente el enlace components.css del HTML. Las formas de los componentes de la tarjeta y del botón desaparecen. Reconecta la ruta a su estado original y actualiza para restaurarlo.

Diagnostica estilos faltantes

Comprueba los problemas de separación de archivos y los conflictos de selectores por separado. Primero, consulta Network o Sources en las herramientas de desarrollo de tu navegador para ver si el archivo se cargó realmente, luego selecciona el elemento para ver si las reglas coinciden en Styles y si alguna declaración ha sido sobrescrita. Si no ves el archivo, revisa la ruta relativa, el nombre del archivo y la extensión, y si no ves la regla, revisa la clase y el soporte de sintaxis.

Incluso si hay una regla coincidente, si ocurre un tachado, compara importancia, capa, especificidad, proximidad del ámbito y orden. Si las variables comunes no son las esperadas, también se debe observar el alcance de la declaración de la variable. Después de la separación, es útil para el mantenimiento volver a revisar la pantalla principal y foco y hover, y corregir las divisiones de responsabilidades y los selectores que causaron conflictos en lugar de seguir agregando declaraciones importantes innecesarias.