El CSS no suele fallar de inmediato. Fracasa un año más tarde, cuando el sistema está en uso real y cambiar cualquier cosa se siente arriesgado. Los estilos comienzan a sentirse pesados.Ustedes abren DevTools, saltan a través de las reglas y tratan de comprender por qué algo funciona de la manera en que funciona.El refactoring se siente mentalmente impuesto y consume tiempo, por lo que añaden otro override sólo para hacer que el billete se vaya. El mal CSS no es sólo feo, es caro.Es por eso que las actualizaciones de UI simples tardan tres días en lugar de tres minutos. El código está haciendo . Demasiado Demasiada especificidad.Muchas decisiones tomadas tempranamente que son demasiado difíciles y demasiado caras para anular. No a través de trucos o herramientas, sino a través de unos pocos hábitos que mantienen CSS simple, legible y barato para cambiar a medida que un proyecto crece. Estas son las cosas que me gustaría haber aprendido antes. Comenzar con CSS es el primer error Sé que el artículo es sobre CSS, pero uno de los errores más comunes que veo que los jóvenes hacen es saltar a una tarea y construir todo de una vez. estilos, JavaScript, marcado, abstracciones tempranas. Normalmente empiezan con la parte más complicada o la más divertida. El CSS es tentador porque es tangible. El mejor enfoque es poner CSS de lado, pausar, ralentizar y comenzar con el marcado. Si estás construyendo una aplicación entera, empieza con la carcasa de la página. Punto de referencia, jerarquía de encabezados, secciones principales. Trabaja en eso primero. Lee la página para empezar a terminar. ¿tiene sentido? sólo pasa a estilos cuando lo hace. Si está trabajando en una función más pequeña, se aplica la misma idea. Coloca primero el marcado y ve cómo se ajusta al resto de la aplicación. ¿las etiquetas coinciden con la intención? ¿Estás respetando el orden de encabezamiento circundante? Comenzando con el marcado te obliga a pensar en la intención, no en la apariencia. No lo que ellos Con un enfoque HTML-first, define la estructura, el significado y las restricciones que mantienen el sistema simple y previsible. son Mirá como CSS should adapt to that, not the other way around. Cuando te apresuras en el estilo, tiendes a dar forma a la marcación alrededor de las señales visuales. envases adicionales. etiquetas equivocadas. Usualmente terminas con cosas que bien, pero son semánticamente equivocados, o imposibles de escalar. mirando Al cometer el marcado primero, se bloquea en una base sólida. Accesibilidad, esquema de documento, flujo de teclado y jerarquía de contenido se resuelven principalmente de antemano. También te ralentiza de una buena manera. Atrapa los casos de borde temprano. Verás dónde las cosas no pertenecen. Puedes retrasar algunas decisiones de diseño. En resumen: HTML-first hace que todo lo demás tenga sentido. Cuando CSS hace más de lo que piensas Otro error común que veo en las revisiones de código es que los jóvenes lo hacen A menudo, sin darse cuenta de ello, os dejo algunos ejemplos. Demasiado Digamos que desea centrar la columna de contenido horizontalmente: .entry-content { max-inline-size: 48rem; margin: 0 auto; /* ❌ Avoid this! */ } Establece una anchura máxima y centra el elemento usando margen automático. Sin embargo, lo que puede no darse cuenta es que también está fijando los márgenes superiores y inferiores a cero. Si eso es intencional, bien. La mayoría de las veces el acrónimo se utiliza simplemente porque es más corto. Lo que probablemente desee en su lugar es esto: .entry-content { max-inline-size: 48rem; margin-inline: auto; /* ✅ Do this */ } El mismo resultado. sin efectos secundarios. más intención. Otro ejemplo común: .button--secondary { background: var(--color--dark-gray); } Establece el color de fondo utilizando el propiedad personalizada, pero también restaura un montón de otras propiedades relacionadas con el fondo. --color--dark-gray Mucho más, en realidad: Imagen de fondo: Ninguna posición de fondo → 0% 0% Tamaño del coche Repetición - Repetición Siguiente Entrada siguiente: Padding-Box Descripción del border-box Atracción de fondo → scroll La mayoría de las veces, eso no es lo que desea. Esto puede llevar fácilmente a efectos secundarios molestos que tendrá que lidiar con más adelante. Lo que probablemente desee en su lugar es esto. .button--secondary { background-color: var(--color--dark-gray); } La misma idea que antes, pero quirúrgica, sólo cambia lo que realmente quieres cambiar. El mismo principio se aplica a otras propiedades cortas, como , de , de , de , y otros. Tenga cuidado al usarlos como cortometrajes.O evitar usar cortometrajes por completo. border transform transition font Un ejemplo más común de hacer demasiado es ser demasiado específico demasiado temprano. a { text-decoration: none; background-image:linear-gradient(to right, currentColor, currentColor); background-position:0%100%; background-repeat: no-repeat; background-size:100%2px; transition: background-size 0.3s; &:hover, &:focus-visible { background-position:100%100%; } } Este fragmento añade un subrayado animado a los enlaces. El problema es que no todos los La etiqueta es un enlace de texto. Las imágenes pueden ser enlaces. Los avatares de perfil pueden ser enlaces. Los botones a menudo están marcados como anclajes. <a> De repente, este estilo global "inteligente" está añadiendo líneas extrañas de 2px bajo su logotipo o rompiendo los gradientes de fondo en sus botones principales. Ahora, pasarás el resto del proyecto luchando contra la cascada, escribiendo estilos "undo" para cada enlace no textual en el que trabajes. visual debt Puede solucionar esto de varias maneras.Una opción es orientar enlaces de texto dentro del contenido. .entry-content:is(h1, h2, h3, h4, h5, h6, p, li) > a { /* styles here */ } Pero incluso esto todavía puede ser demasiado estrecho o demasiado ancho, dependiendo del marcado. Mi método favorito es una clase de utilidad. .has-animated-underline { /* styles here */ } Al mover esto a una clase, haces el comportamiento Es explícito, intencional, y, lo más importante, no requiere que usted arregle cosas que no se rompieron en el primer lugar. opt-in rather than opt-out Cuando el móvil es una reflexión posterior Sin embargo, todavía veo a los diseñadores que pasan la mayor parte de su tiempo trabajando en compilaciones de escritorio y presentando el trabajo de escritorio primero, con los móviles tratados como una simple versión "estacada" del escritorio. Esto todavía se siente hacia atrás. Qué te guste o no, experimentamos Internet a través de un teléfono primero. que puede cambiar de nuevo, pero es la realidad hoy. La forma en que construimos la web debe reflejar eso. En la práctica, así es como me acerco al estilo ahora: Deja el marcado (habló sobre ello 😉). Redimensionar el navegador a alrededor de 400px y estilizar la aplicación o función como si el escritorio no existiera. Una vez que funcione en móvil, redimensione el navegador a escritorio y haga un segundo paso en los estilos. Trabajar de esta manera naturalmente te lleva al 80% (número aleatorio que parece correcto) en términos de hacer que tu proyecto sea accesible y listo para pantallas pequeñas. Esto nos lleva orgánicamente a la implementación mobile-first. Cuando empecé a hacer el desarrollo web, las consultas de medios eran apenas una cosa.No navegábamos por la web en teléfonos. Luego salió el iPhone, y las consultas de medios se convirtieron en la principal herramienta para los diseños responsivos.El número de dispositivos web-capaces era limitado, por lo que se podía salir con un rígido conjunto de puntos de interrupción: /* phones */ @media (max-width: 480px) {} /* large phones and small tablets */ @media (max-width: 767px) {} /* tablets */ @media (min-width: 768px) and (max-width: 1024px) {} /* desktop */ @media (min-width: 1025px) {} Tenga en cuenta que esto no es ni siquiera móvil-first. el enfoque. min-width Hoy en día, la realidad es diferente.Hay demasiados dispositivos y tamaños de pantalla para diseñar para usar los puntos de interrupción solos.A menudo es más inteligente confiar en herramientas que se adapten naturalmente a toda la gama. Por ejemplo: Layouts intrínsecos con Grid o Flexbox Valores fluidos utilizando clamp() para tamaños de fuente, espaciamiento y dimensiones Contenedor de Deseos Las consultas de medios todavía son útiles, pero no deben ser la primera herramienta a la que llegue. Si un diseño sólo funciona debido a los puntos de interrupción, es probablemente demasiado rígido. Cuando funciona sin ellos, las consultas de medios se convierten en pequeños ajustes intencionales a la estructura responsiva, no a la fundación. Combatir la cascada en lugar de usarla Este es otro área donde a menudo veo a los ingenieros junior luchar. Un montón de marcos y soluciones CSS existen para resolver una característica principal: la cascada.Y me doy cuenta de por qué.Si saltas a CSS sin mucha experiencia, puede parecer caótico. Escribe una regla y no hace nada. Lo ajusta y de repente algo más se rompe. Además, la hoja de estilos del agente de usuario está haciendo su propia cosa en el fondo. Eso es frustrante porque CSS no es nada como la mayoría de los otros idiomas. En JavaScript, puedes crear un módulo y nada se escapa. No puedes acercarte al CSS de la misma manera.Si lo intentas, te morderá muy duro en la cara. Cada cambio de CSS vive en dos ámbitos a la vez: la cosa que está estilizando y el resto del sistema en el que fluye. Volviendo al ejemplo anterior, no puedes simplemente escribir esto: a { text-decoration: none; background-image:linear-gradient(to right, currentColor, currentColor); background-position:0%100%; background-repeat: no-repeat; background-size:100%2px; transition: background-size 0.3s; &:hover, &:focus-visible { background-position:100%100%; } } Si lo hace, esto aplicará propiedades relacionadas con el fondo a cada ancla en la página, incluso si esa ancla no es un enlace de texto. La mayor parte del tiempo, eso no es lo que quieres. Algunos ingenieros aprenden esto de la manera difícil y responden evitando la cascada por completo, como tocar un horno caliente como un niño y aprender a no hacerlo nunca más. Creo que es un error porque conduce a mucha repetición. Aquí está un ejemplo de un proyecto reciente en el que trabajé. @define-mixin focus-state { &:focus-visible { outline: var(--outline--color) var(--outline--style) var(--outline--width); outline-offset: var(--outline--offset); } } Entonces se incluyó en varios componentes: .button { @mixin focus-state; } a { @mixin focus-state; } .pagination-link { @mixin focus-state; } ...y así sucesivamente. Los enfoques deben ser consistentes en todo un proyecto, con muy pocas excepciones. En esta configuración, cada llamada de mixin genera el mismo CSS una y otra vez. Un enfoque más elegante es apoyarse en la cascada y definir esto globalmente: :focus-visible { outline-color:var(--outline--color); outline-offset:var(--outline--offset); outline-style:var(--outline--style); outline-width:var(--outline--width); } Ahora cada elemento que recibe un estado de enfoque visible recibe el mismo estilo por defecto. Y en los raros casos en los que algo necesita ser diferente, puede superarlo localmente: .pagination-link { --outline--offset: -2px; } Eso es lo que es. Simples, compacto y previsible. El mismo concepto se aplica a cosas como , de Margen de reset, , y otros estilos que deben comportarse de manera consistente en toda la aplicación. box-sizing ::selection text-wrap Una rápida comprobación del corazón ayuda aquí. si un estilo se ve Lo mismo ocurre con todos los componentes, con excepciones, probablemente pertenezca a sus estilos globales. exactly very few No ignores la cascada, utilízala a tu ventaja. La especificidad es donde las cosas continúan cayendo por separado Esto suele ser la razón detrás de "He escrito mi CSS pero no funciona". No voy a entrar profundamente en qué es la especificidad.MDN ya Lo importante aquí es que la alta especificidad es una de las principales fuentes de dolor al trabajar con bibliotecas de terceros o el código de otra persona. Lo hace realmente bien Tomemos este ejemplo: .layout > :not(.alignleft):not(.alignright):not(.alignfull):not(.alignwide) { max-width: var(--content-width); margin-left: auto; margin-right: auto; } Aquí nos centraremos los hijos inmediatos de horizontalmente y aplicar un ancho máximo - todos los niños excepto , de , de , y . .layout alignleft alignright alignfull alignwide Hay dos razones principales por las que este código huele. Primero, este es un patrón de lista negra.Estamos estilizando todo El problema es que "todo" siempre cambia con el tiempo. A medida que el proyecto crece, casi seguramente agregarás más excepciones. excepto En segundo lugar, cada selector que añadas aumenta la especificidad. Esto significa que superarlo requiere un selector aún más fuerte, , de o envuelve todo en En otras palabras, correges la complejidad con más complejidad. 0.5.0 !important @layer :where() WordPress es un buen ejemplo de comenzar sin arquitectura CSS y terminar con el caos. body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; } Estoy recibiendo señales mixtas aquí. Nos arrodillamos con la el patrón, se dio cuenta de que era una mala idea, recuperado con Y luego... aplicado Estoy seguro de que había una razón para esto, pero el hombre... ¿no es tan frustrante? :not() :where() !important Seguro que puedes hacer todo esto... O puedes ser más intencional y comprarte un poco de paz: /* 0.1.0 */ .layout > * { max-width: var(--content-width); margin-left: auto; margin-right: auto; } /* 0.2.0 */ .layout > .alignleft, .layout > .alignright { --content-width: var(--content-width--narrow); } /* 0.2.0 */ .layout > .alignwide { --content-width: var(--content-width--wide); } /* 0.2.0 */ .layout > .alignfull { --content-width: var(--content-width--full); } Esto es más fácil de leer y más fácil de razonar.La regla básica es Las excepciones son . 0.1.0 0.2.0 Predecible y intencional. Aquí hay otra forma común de que la especificidad crezca sin buena razón: /* ❌ combine element with a class ❌ element nested inside the block ❌ modifier nested inside the block */ a.button { &.button__label {...} &.button--secondary {...} } En este ejemplo: Si no hay razón para combinar a y .button, no lo hagas. Si no hay razón para anexar el .button__label bajo el .button, no lo haga. Lo mismo ocurre con las clases modificadoras. Si está enviando un nuevo componente, esto suele ser lo que desea en su lugar: /* ✅ no element + class combination ✅ elements and modifiers stay flat */ .button {...} .button__icon {...} .button--primary {...} Aquí está la regla del pulgar que sigo: Prefiere un único selector de clase por defecto. Utilice variaciones de utilidad en lugar de empacar selectores. orden de fuente te ayudará aquí. Mantenga la especificidad en 0.1.0 o 0.1.1. No vayas por encima de 0.2.0 en las características que envías. Evite los selectores #id y los estilos en línea en el código de la aplicación. Utilice una especificidad más alta sólo cuando supere el código de terceros o legado que aún no puede refactor. Notas en , de , y :where() @layer @scope Estoy plenamente consciente de estas herramientas. Puedes reducir la especificidad a cero con Aislamiento de estilos con , y selectores de alcance con . :where() @layer @scope Son poderosos, y tienen su lugar, pero no arreglan la mala arquitectura. Las mismas reglas de especificidad todavía se aplican dentro de cada capa y dentro de cada ámbito. Mantén la especificidad baja.Tu futuro yo te agradecerá.