Reglas CSS que te facilitarán la vida

Después de años de escribir y mantener un par de proyectos web muy grandes y muchos más pequeños, he desarrollado algunas heurísticas para escribir CSS mantenible. He usado módulos BEM, SMACSS y CSS para nombrar, aunque este artículo no trata sobre nombres en sí. (Tiendo a usar una combinación de clases atómicas y nombres similares a BEM). Este artículo trata más sobre las propiedades y valores que uso o evito.

Mi configuración de StyleLint: //github.com/NickGard/css-utils/blob/master/stylelint.config.json

Colores

Una de las cosas que más me molestan es la sobreabundancia de valores de color en un proyecto web. Un proyecto grande y de larga duración en el que trabajé hace unos años tenía más de 300 colores únicos declarados en 40 archivos CSS. Un tercio de estos eran tonos de gris. Los colores de la marca se repitieron con ligeras diferencias de tonalidad. Muchos de estos colores se diferenciaban por valores literalmente imperceptibles, como #3426D1y #3426D2. La solución a esto es utilizar clases de colores atómicos o variables (en SCSS o CSS) para los colores de marca aceptados.

Limitar el número de colores aceptados tiene el beneficio adicional de simplificar la tarea de garantizar que los colores de fondo y primer plano cumplan con las pautas de Contraste de color WCAG2.0.

Otra práctica propensa a errores es usar colores de canal alfa, generalmente declarando el color con funciones rgba()o hsla(). Un color creado de esta manera con un valor de canal alfa distinto al 1semiopaco. El color percibido ahora cambia según lo que haya en el fondo . Por lo general, el color deseado es el que tiene este sobre un fondo blanco, por lo que puede usar un valor hexadecimal en su lugar. Algunas funciones del preprocesador, como las de SASS lighten(), generarán un color semiopaco, así que apéguese a valores o variables codificados de forma rígida.

Tipografía

Todas las propiedades que afectan o se ven afectadas por la fuente deben declararse una vez juntas. Justo después de declarar cualquier @font-facereglas, me gusta añadir clases atómicas para el tipo de letra que el cambio del font-size(a través de rem) e incluyen line-height, letter-spacingy word-spacingque sean apropiados para esa combinación de fuente y el tamaño. Después de eso, no se debe usar ninguna propiedad font-*o text-*(con la excepción de text-overflow) en ningún conjunto de reglas.

Declarar estas propiedades una vez junto con el tipo de letra garantiza que la copia en el sitio siempre se vea bien. Ajustar el en line-heightlugar de paddingo margincreará errores cuando el texto se ajuste . Si se ajusta por font-weightseparado de la declaración de la fuente, se corre el riesgo de crear una fuente falsa en negrita. Cambiar font-styleuna fuente que no la admite crea una falsa oblicua.

Por último, evite establecer tamaños de fuente que no sean remunidades. El uso emcausa problemas al anidar elementos porque emes un múltiplo escalar de la corrientefont-size . El uso px(o cualquier otra medida "fija") corre el riesgo de crear una copia que sea difícil de leer e imposible de ajustar para el usuario. Permita que el usuario (o el navegador del usuario) establezca el font-sizeen lo que es correcto para ellos al no declarar un font-sizeen el elemento bodyo htmly solo usar rem.

Espaciado

En un sitio de contenido primero, el espaciado debe complementar la copia. Cualquier medida estática, como padding: 4px, se ve mal con algún tamaño de fuente. Una medida dinámica que responde a los tamaños de fuente, como padding: .5em, se ve bien en cada tamaño de fuente.

Úselo empara propiedades de espaciado.

Cuadrícula

CSS Grid está muy bien soportado (¡de regreso a IE10!) Y permite la organización del contenido en dos dimensiones sin elementos contenedores agregados como Bootstrap rowo colelementos de cuadrícula. Los diseñadores a menudo trabajan en cuadrículas de 12 columnas y los marcos CSS tienden a seguir su ejemplo, pero las cuadrículas, como todos los espacios, deben complementar la copia, no restringirla. Las cuadrículas deben escribirse ad hoc, no en un formato predeterminado sin contexto. No infle su CSS con un "marco de cuadrícula".

Alineación del texto

text-alignse utiliza a menudo para alinear elementos que no sean texto. Ésta no es la herramienta adecuada para el trabajo. Utilice flexbox para este tipo de alineación. El uso de valores left y rightno siempre funciona con lenguajes de derecha a izquierda o verticales (algunos navegadores asignan estos valores al flujo relativo starty end, pero no a todos). Usar el valor justifyen el texto puede causar problemas en algunos idiomas con dígrafos y puede causar problemas a las personas con dislexia. Cada caso de uso para text-alignse resuelve mejor con flexbox, así que úselo en su lugar. Siempre.

Contornos

Los contornos de elementos enfocados son cómo los navegadores comunican de forma nativa qué elemento está recibiendo entrada. Los contornos predeterminados suelen ser lo suficientemente prominentes como para ser útiles para todos los usuarios, incluidos aquellos que necesitan un alto contraste. El esquema predeterminado generalmente se sobrescribe (o elimina) porque no encaja con el diseño del sitio. A menos que esté reemplazando el outlineestilo enfocado con algún otro indicador de enfoque prominente y accesible, no elimine ni anule la propiedad de contorno .

Enfoque y desplazamiento

Como se mencionó anteriormente, tenga cuidado con cambiar el :focusestilo porque actúa como un indicador para qué elemento está recibiendo entrada actualmente. Agregar estilos a un elemento en :hoversuele ser un buen toque, pero no use ese pseudo-selector para mostrar una copia adicional a menos que haga lo mismo para :focus(y, por supuesto, si el elemento es enfocable ). Por lo general, pero no siempre, una idea buena para usar tanto las :hovery :focuslos pseudo-selectores para el mismo conjunto de reglas. (Agregar el :focusselector a los estilos de desplazamiento del mouse para un botón puede hacer que el botón presionado parezca "atascado").

Opacidad

Configurar el opacityde un elemento en 0no lo oculta realmente de las herramientas de accesibilidad. El elemento todavía ocupa espacio en el flujo del documento y los lectores de pantalla aún leen su copia. Los únicos dos casos de uso que requieren razonablemente el uso de la opacitypropiedad son cuando se hace la transición de un elemento a la vista (transición rápida de 0a 1) y cuando se aplica estilo a una superposición de diálogo (por lo que el contenido a continuación es algo visible). Tenga cuidado con las superposiciones semiopacas "apiladas". El nivel de opacidad es multiplicativo, por lo que el contenido debajo de dos superposiciones, cada una con, opacity: 50%se muestra como si estuviera debajo de un solo elemento con opacity: 25%.

Selectores

Cíñete a usar selectores de clases y similares. El uso de selectores de identificación, tipo y universal conlleva dolores de cabeza. En la especificidad de CSS, los selectores de ID siempre ganarán contra cualquier otro selector, pero idse supone que los atributos son únicos (por página), por lo que no son útiles para aplicar estilos reutilizables.

El rendimiento del selector en los navegadores modernos es una preocupación insignificante, por lo que a pesar de lo que puede haber escuchado acerca de que el selector universal ( *) no funciona, mi verdadera preocupación con su uso es que es demasiado general para casi todos los casos de uso. Usando algún selector como .my-class >; * eventualmente conducirá a la exclusión voluntaria de algún niño, por lo que también podría agregar clases a los elementos que desea diseñar y orientarlos directamente.

Un argumento similar puede hacerse para no utilizar selectores de tipo, como div, main. Suelen coincidir con demasiados elementos y normalmente requieren más detalles para ser útiles, como div.some-class. Los selectores compuestos como este tienen una mayor especificidad que un solo selector de clase, un problema de generación de errores que se aborda a continuación.

Cíñete a los selectores de clase ( .class), atributo ( [attribute]) y pseudoclase ( :focus). Todos tienen el mismo nivel de especificidad.

Especificidad

At the opposite end of the spectrum of selectors being too general (like using *) are selectors being too specific. Both cases cause problems. An overly-specific selector breeds even more specific selectors or the dreaded !important declarations. Each successive selector becomes a new hurdle to overcome when making styling changes, and following this path leads to the ever-growing fragile stylesheets we all dread working with.

CSS has a naturally increasing specificity — the order of the rulesets. This is part of the cascade in Cascading Style Sheets. With this in mind, we can write rulesets in ascending order of “importance” without increasing the selector specificity level. For example:

.btn { color: black;}.btn--primary { color: green;}.btn--primary--light { color: white;}

In this example, each single-class-selector is more specific than its predecessor, eliminating the need to declare a ruleset for .btn.btn--primary or .btn.btn--primary--light.

The fix is to stick to single class selectors as much as possible, written in order of increasing “importance,” and avoid using !important declarations.

Text-transform

For sites that support languages other than English, using text-transform will probably cause problems. There are several cases where browsers replace a character with an incorrect version for the upper- or lower-case transformations. The fix is never to use text-transform and instead rely on an accurately capitalized copy.

Z-index

If any z-index rule is included in a stylesheet, there will eventually be two other rules that declare z-index: 9999; and z-index: 99999;. Attempting to use atomic classes or variables to limit the number of acceptable z-indexes will not only fail to curb developers from using calc() and SCSS math to modify the value for their use-case, but will miss the target entirely because of how stacking contexts work.

It has been my experience that most, if not all, uses of z-index can be replaced by restructuring the HTML to use the natural stacking context (elements lower on the page are higher in the context) or by adding a property to the element or its parent to force a new stacking context.

Avoid z-index at all costs.

Pseudo-elements

Using the pseudo-elements ::before and ::after is not only helpful, but it’s often fun! Many stylistic tricks rely on the use of these two pseudo elements and, as long as there is no copy in them (via their content property), they are considered semantic. The issue with putting copy in these elements is that whether or not they are read by accessibility devices varies across browsers and devices. It is better to not deal with that discrepancy by avoiding placing a copy in them.

The pseudo-elements ::first-letter and ::first-line do not work like you probably think they should. They only target the first letter/line in a block-level element. There are also issues with the ::first-line selector incorrectly targeting double-byte characters (such as Japanese Kana) and digraphs.

Manipulating the styles of selected text or placeholder text via ::selection and ::placeholder, respectively, often leads to trouble. With ::placeholder, the concern is simple: you shouldn’t be using placeholders. This is especially true for anything of importance, such as input labels or hints. By including ::placeholder styles, you encourage developers, designers, and authors to use them, much to the frustration of your users.

Modifying selection styles, usually color and background-color, leads to more subtle but insidious bugs. While the default selection colors are not consistent across browsers or devices and they do not always provide an acceptable contrast with your site’s text color, users sometimes overwrite them for accessibility reasons. Changing the colors, in this case, could either not work (because of the user’s accessibility CSS trumps yours) or it could interfere with their style sheets (if you use !important). Using this pseudo-element to try to guarantee an accessible contrast could end up disrupting the experience for the very people you wish to help.

(Though I’ve forgotten many of the details of this bug, I ran into an issue years ago where Chrome’s auto-translated text was rendered invisible because it relied on ::selection styling which I had modified.)

Transitions & Animations

Transitioning or animating properties other than opacity and transform causes the browser to repaint or reflow the page. This may not seem like a problem on a high-end developer machine, but it will cause stuttering on low-end laptops and phones. Bad animation is worse than no animation.

Prefers Reduced Motion

Writing animations that are helpful, beautiful, and safe is not a simple undertaking. With the advent of the media query prefers-reduced-motion, we can help make our pages safer for people with vestibular disorders, and less annoying for the rest of us. While adding this media query is not a silver bullet, it helps. I’ve written the nested rule to be opt-out, meaning that all CSS animations get stopped unless the author includes the class safe-animation on the element.

/* //github.com/mozdevs/cssremedy/issues/11#issuecomment-462867630 */@media (prefers-reduced-motion: reduce) { *:not(.safe-animation), *:not(.safe-animation)::before, *:not(.safe-animation)::after { animation-duration: 0.01s !important; animation-iteration-count: 1 !important; transition-duration: 0s !important; scroll-behavior: auto !important; }}

Reset extensions

My go-to CSS reset is a modified form of the Meyers reset. There are a few rules I remove from the reset, though. I don’t like to remove list icons from ol and ul elements. I find that doing so encourages developers to use those elements in non-semantic ways, like grouping items that are physically proximate but not ontologically proximate. I also remove the rule setting the line-height on the body to 1. Setting attributes that affect, or are affected by, the font separately from setting the font is a bug waiting to happen.

Algunas de las adiciones que realizo al archivo de reinicio se encuentran a continuación. No me gusta incluir una .hiddenclase atómica en mi CSS porque hay una mejor opción que funcionará incluso si el CSS no se carga: el hiddenatributo. El comportamiento predeterminado del navegador de configurar display: noneelementos ocultos se puede sobrescribir, incluso accidentalmente, por lo que incluyo una regla para hacer cumplir.

body { /* more intuitive sizing */ box-sizing: border-box;}*, ::before, ::after { box-sizing: inherit;}i, cite, em, var, dfn, address { /* prevent faux italic */ font-style: normal;}b, h1, h2, h3, h4, h5, h6, strong, th { /* prevent faux bold */ font-weight: normal;}[hidden] { /* enforce accessible semantics */ display: none !important;}
Mi reinicio: //github.com/NickGard/css-utils/blob/master/reset.css

Otra utilidad que a menudo encuentro necesaria es una visually-hiddenclase. Si bien lo uso aria-labelmás a menudo para texto invisible legible en pantalla, generalmente incluyo la siguiente regla en alguna parte:

/* //a11yproject.com/posts/how-to-hide-content/ */.visually-hidden { position: absolute !important; height: 1px; width: 1px; overflow: hidden; clip: rect(1px, 1px, 1px, 1px);}

Nombrar BEMish

Original text


No puedo terminar este artículo sin al menos un comentario sobre las convenciones de nomenclatura. Me gusta el nombre de BEM porque se lee bien. /> tells me exactly what kind of button it is. My one break from the Official BEM™ methodology is that I like to use one class on an element (with the possible exception of atomic classes). It offends my sensibilities to see