CSS: las partes malas inevitables
(matklad.github.io)- Para estilizar una página web, basta con aprender un pequeño subconjunto para un blog simple o una GUI, pero trampas como los valores por defecto del navegador y el layout pueden terminar en días de debugging
- Si primero usas etiquetas HTML5 semánticas y reduces los wrappers, es más fácil hacer que CSS funcione con el markup existente
- En el layout de CSS no existe un único algoritmo universal, y hace falta un enfoque que entienda qué tipos de disposición permite cada sistema
box-sizing,margin,font-size,line-heightyword-breakfuncionan distinto a la intuición, y cambios pequeños pueden convertirse en problemas de distribución general o legibilidad- Para páginas simples, un CSS reset, CSS sin clases, flexbox y reglas responsive no excesivas pueden ser un punto de partida práctico
Alcance del aprendizaje de CSS y perspectiva básica
- CSS, HTML y las Web API son enormes y requieren especialización, pero para trabajos como un blog de programación o una GUI simple, basta con un subconjunto razonable de la web moderna
- No he visto materiales que enseñen solo el subconjunto necesario para tareas simples, pero siguiendo MDN se puede entender bastante
- El problema es que trampas cuya existencia uno no anticipa pueden arruinar la página, y encontrar la causa puede tomar días
- El estilo de este sitio está compuesto por unas 200 líneas de CSS legible
La parte buena: HTML con significado y CSS sin clases
-
Etiquetas semánticas de HTML5
- Vale la pena revisar la referencia de elementos de MDN, y la cantidad de elementos HTML no es tan grande
- Etiquetas como
main,article,navykbdpueden hacer más fácil estructurar la página ulpuede usarse para todo tipo de listas, como las secciones del sitio dentro deheader > navdetailspuede usarse para una tabla de contenido, y se puede revisar el código fuente de MDNdlydtpueden usarse para listas de pares
-
Un enfoque para reducir wrappers
- Si miras el código fuente de sitios web reales, hay muchos elementos wrapper anidados, y puede parecer que los problemas de layout se resuelven con wrappers
- Sin juzgar la experiencia de CSS en producción, me resultó más fácil de entender el enfoque de limitarse a usar solo etiquetas semánticas con significado y luego encontrar un CSS que encaje con ese markup
-
CSS sin clases
- No se puede reiniciar el estilo a un estado completamente neutral de “no hay nada”; incluso texto blanco o transparente sigue siendo un estilo
- Después del reset, es posible estilizar directamente los elementos HTML comunes
- Si usas etiquetas
main,header,footerynav, puedes definir el layout general de toda la página sin usar muchos selectores CSS - Este enfoque hace que CSS asuma la estructura del HTML, pero si el HTML y el CSS son tuyos, puedes cambiarlos si no te gusta el resultado
La parte mala: layout, valores por defecto del navegador y selectores
-
Layout
- Los problemas de layout no son exclusivos de la web; también son difíciles en varios frameworks de GUI
- Hay muchas formas de colocar dentro de un rectángulo de pantalla una imagen raster de tamaño fijo y un párrafo de texto que la describa
- Una GUI general es una estructura jerárquica de cajas con mucha “libertad de layout”
- El layout de cada caja afecta el layout de todas las demás, y normalmente todas deben encajar exactamente sin espacios ni superposiciones
- No existe un único algoritmo universal de layout; cada sistema usa heurísticas distintas, desde RectCut hasta constraint solvers, pasando por la zona intermedia
- Es mejor pensar “¿qué layouts permite este sistema?” que “¿cómo hago este layout en este sistema?”
-
Valores por defecto del navegador y CSS reset
- Incluso HTML semántico sin CSS recibe estilos por defecto del navegador, como color, tipografía, tamaño, títulos grandes y enlaces subrayados
- Los estilos por defecto son útiles, pero varían entre navegadores, y si dependes de valores que no escribiste, puedes ver resultados distintos en otros navegadores
- La solución habitual es un CSS reset o una normalización, es decir, sobrescribir los valores por defecto con reglas explícitas al inicio del CSS
- El problema no es que los valores por defecto sean malos, sino que no son consistentes entre sí
- Para saber qué reglas conviene sobrescribir, es mejor comparar varios CSS reset ya existentes
-
¿Deberíamos estilizar páginas web?
- En la plataforma web conviven la idea de verla como un medio visual flexible y adaptable, y la idea de centrarse en entregar contenido para que el usuario personalice la presentación
- Una página sin estilos, por defecto, tiene baja usabilidad y no se ve bien
- Sería mejor un mundo donde una página sin CSS siguiera siendo fácil de leer, pero en el entorno actual aplicar estilos al contenido sí ayuda
- Es bueno permitir que usuarios avanzados puedan traer su propio CSS
- El marcado HTML debe ser razonable, no debe sobreajustarse al CSS, y la página debe funcionar en reader mode
-
Selectores CSS
- El CSS básico funciona como una herencia potente, y cada elemento visual de una página puede verse afectado por varias reglas
- Se puede “monkey patch” cualquier elemento existente en cualquier momento simplemente agregando al archivo CSS
- Considera que los selectores CSS agregan capacidad de abstracción sobre el eje equivocado, y por eso es viable un enfoque con CSS sin clases e inline style
- Herramientas como Tailwind reducen la incomodidad de escribir inline, y motores de plantillas con soporte para JSX o composición reducen la repetición de HTML
- Usar CSS nesting permite reducir selectores que se extienden demasiado y estilizar por componente
Modelo de caja y distribución: box-sizing, margin, flujo por defecto y flexbox
-
box-sizing- La UI es un conjunto recursivo de rectángulos, y el layout es el proceso de decidir dónde se coloca cada rectángulo
- En los valores por defecto de HTML,
widthyheightde un elemento no incluyen el borde ni el padding, lo cual no es intuitivo - Si aumentas el padding en un solo lugar, un layout general que al principio parecía perfecto puede desplazarse inesperadamente
* { box-sizing: border-box; }merece ser la primera línea de un CSS reset, porque hace que agregar un borde sea un cambio local
-
Margin collapsing
- Si quieres un espacio de
8pxalrededor de un elemento y usas padding, el espacio entre dos elementos adyacentes puede terminar siendo de16px marginfunciona combinando los márgenes de dos vecinos no con suma, sino conmax- El margin collapsing es muy útil, pero puede producir comportamientos sorprendentes
- Se puede pensar que el margin de un hijo puede salirse fuera del padre, aunque no haya una intuición suficiente sobre
margin - El texto de Julia Evans Moving away from Tailwind, and learning to structure my CSS trata, en general, de la estrategia del owl selector, donde el padre controla el margin entre hijos en vez de asignarlo al propio elemento
- Entiendo que agregar margin a todos los hijos de
sectionexcepto el primero es una idea para reducir problemas con margin - Es incómodo que este tipo de conocimiento sea difícil de aprender si no te conviertes en desarrollador web profesional o haces ingeniería inversa de otros frameworks CSS
- Si quieres un espacio de
-
Layout de flujo por defecto
- El algoritmo de layout por defecto parece estar relacionado con el origen de HTML como lenguaje de documentos y con casos de uso orientados a generar documentos en papel centrados en texto e imágenes
- Para el texto principal, el flujo por defecto sí se comporta bastante cerca de lo que uno quiere
- Si quieres controlar directamente la distribución espacial de elementos de página, necesitas algo distinto del flujo por defecto
-
Flexbox
- Flexbox es un layout para organizar una serie de elementos en vertical u horizontal y adaptarlos al espacio disponible
- Antes, incluso para algo como “esto a la izquierda, esto a la derecha”, hacía falta conocimiento profundo de CSS o un framework CSS opaco
- Flexbox es bastante complejo y obliga a seguir consultando MDN, pero en general permite terminar lo que quieres hacer
-
Diseño responsive
- El CSS moderno permite consultar el tamaño de la pantalla e implementar lógica condicional según las restricciones del user agent
- HTML es responsive por naturaleza y, a diferencia de PostScript o PDF, vuelve a fluir los párrafos automáticamente cuando cambia el tamaño de la ventana
- Conviene evitar reglas responsive explícitas y dejar que el layout se comporte de manera razonable por sí solo
- Este blog se ve bien en móvil, tablet y desktop sin
@mediaqueries explícitas - Basta con poner un
max-widthincondicional a la columna principal del texto
Tamaño y texto: píxeles, tipografías, altura de línea y saltos de palabra
-
Píxeles
1pxhace lo que uno espera, pero no significa un único píxel físico de la pantalla1pxen CSS es una unidad de ángulo visual, diseñada para verse perceptualmente parecida en cualquier pantalla- Se convierte en distintas cantidades de píxeles físicos según el tamaño de la pantalla, la densidad de píxeles y la distancia habitual de visualización
- Por eso se puede especificar todo en píxeles sin pensar por separado en la densidad de píxeles de cada pantalla
- Incluso las unidades “reales” de CSS, como centímetros y pulgadas, se definen en función del píxel, así que también funcionan como ángulos
-
font-size- En
font-size: 16px,16pxno es el tamaño de un glifo específico, sino el tamaño de una caja virtual alrededor del glifo - Esa caja no ajusta exactamente al glifo, y el tamaño real del glifo varía según la fuente
font-size-adjustpuede hacer quefont-sizesea más consistente entre fuentes- Hoy
font-size-adjustparece una función muy de nicho, y personalmente quisiera ponerfont-size-adjust: ex-height 0.53;junto abox-sizing, pero pocas páginas lo hacen - El valor por defecto de
font-sizees relativamente consistente entre navegadores, y16pxes abrumadoramente el valor predeterminado - Según la fuente,
16pxpuede verse pequeño, y algunas fuentes por defecto se ven especialmente pequeñas - En Apple,
font-family: serifse ve mucho más pequeño quesans-serif, y con16pxcasi resulta incómodo de leer - Cuando defines
font-sizeen CSS, desactivas la forma en que el navegador cambia el tamaño de fuente por defecto - No debes asumir que el texto será legible por defecto; hay que comprobarlo con otras configuraciones
- Si reduces grados de libertad con
font-size-adjusty fijas el significado defont-size, entonces si se ve bien con el tamaño de fuente predeterminado de16px, ya está - Si no, hay que poner un número mayor en
font-sizey luego verificar que siga siendo legible también en reader mode
- En
-
line-height- A pesar del nombre,
line-heightno define la altura de una línea line-heightes la altura de un conjunto de glifos configurados con la misma fuente- Cuando todo el texto usa la misma fuente, la altura de línea y la altura del conjunto de glifos coinciden
- Si algunas palabras usan una fuente
monospace, pueden aparecer resultados distintos a los esperados font-size-adjustcorrige el tamaño del glifo dentro de la caja, pero no define también su posición relativa- Cuando conjuntos de texto con distintas fuentes se alinean verticalmente para compartir la misma baseline, las line-box de
line-heightde cada uno quedan desalineadas - La altura total de la línea puede construirse como una unión y terminar siendo mayor de lo esperado
- Este efecto se explica en detalle en Deep dive CSS: font metrics, line-height and vertical-align
- A pesar del nombre,
-
Vertical rhythm
- El vertical rhythm es la idea de mantener las líneas entre párrafos en la misma posición relativa aunque haya títulos, imágenes, etc.
- Se explica como si detrás de la página web hubiera una hoja rayada invisible
- Se considera que no es útil en layouts de una sola columna
- En un layout de dos columnas, sí podrías querer alinear las líneas de ambos lados
- En una sola columna no tiene sentido hacer un esfuerzo complejo para lograrlo
-
word-break- La ventaja del layout de flujo es su comportamiento dinámico: cuando la ventana se angosta, el texto se divide limpiamente en líneas
- Las líneas solo pueden cortarse en espacios en blanco o en puntos donde se puede insertar un guion
- Tramos largos como
inline codeo una URL pueden no cortarse - En móvil, este problema produce overflow horizontal, y normalmente uno lo descubre solo después de publicar
- No hay un truco único para arreglarlo, pero Against Horizontal Scroll tiene algunos consejos
Conclusión práctica
- Hace falta material que explique de forma breve una parte suficiente de HTML y CSS para crear un blog simple
- El texto cierra pidiendo un libro corto, de unas 100 páginas, que explique HTML y CSS lo suficiente como para hacer un blog sencillo sin venirse abajo por problemas como el margin collapsing
1 comentarios
Opiniones en Lobste.rs
Es una observación menor, pero la definición de responsive design es “hacer que se renderice bien en distintos dispositivos y tamaños de ventana/pantalla para garantizar usabilidad y satisfacción”
Las media queries o container queries son solo una de las herramientas para implementarlo, y el diseño responsivo se parece más a una forma de pensar que a “usemos media queries para todo”
Por eso, parece más correcto considerar que lo “malo” no es el diseño responsivo en sí, sino las media queries o el abuso de breakpoints
La parte de “Browser defaults” lleva bastante a confusión. Las hojas de estilo de reset y las hojas de estilo de normalización tienen objetivos y comportamientos muy distintos, y el artículo las mezcla
Un reset, más que eliminar diferencias entre navegadores, borra las diferencias predeterminadas entre elementos, quitando cosas como
padding-inline-startdeolo la apariencia por defecto debutton, y te permite crear estilos desde una hoja en blanco en vez de partir de la stylesheet del user agentLa normalización es un enfoque que busca colaborar con la stylesheet del user agent, y mezcla partes que alinean diferencias entre navegadores con partes que cambian valores por defecto a otros considerados “más razonables”
Hoy en día ya no hay muchos casos donde los valores por defecto del navegador difieran de forma significativa, así que quien escriba contenido web normal puede ignorarlo casi por completo. Como excepciones quedan Chromium has the wrong
tableborder-color, WebKit fixed theirs 1½ years ago, algunas diferencias de margen/tamaño en ciertos controles de formulario,appearancey el styling de::markerde<summary>en WebKitTambién estoy en contra de
box-sizing: border-box.border-boxestá centrado en el layout ycontent-boxen el contenido, así que me parece mejor que el padre se encargue del layout y diseñar con el contenido como referencia. Al trabajar con proporciones,content-boxes necesario, y el único caso dondeborder-boxrealmente resulta útil es algo como hacer quebodyllene el viewportTambién soy escéptico con
font-size-adjust. Cambia un problema bien conocido por otro menos comprobado: para algunas personas puede ser un poco mejor y para otras un poco peor. No resuelve el problema de fondo, y obliga a hacer suposiciones sin base sobre las proporciones y métricas de la fuente del usuarioLa expresión sobre
line-heighty “configurarlo con la misma fuente” tampoco es precisa. En la práctica están involucrados el tamaño de fuente, los cambios de idioma,font-family: monospace,vertical-align,<sup>,<sub>y las métricas tipográficas, así que cuesta verlo como un simple problema de “misma fuente”El colapso de márgenes es más complejo de lo que sugiere el artículo, pero también bastante práctico. Si usas
flexogridpara contenido general, terminas ajustandogapo márgenes constantemente y eso puede volverse frágil. Condisplay: flow-rootpuedes evitar que los márgenes de los hijos colapsen con los del padreNo coincido con el marco general sobre diseño responsivo, pero sí con la idea de reducir media queries innecesarias y no pelearse con el navegador. Si puedes expresar cambios de layout en función del contenido, por lo general esa opción es mejor
Últimamente uso mucho la interpolación lineal con clamp usando unidades de viewport:
margin-inline: --vw-lerp(1rem at 20rem, 2.5rem at 60rem);, expandiéndolo comomargin-inline: clamp(1rem,1rem + ((2.5 - 1)/(60 - 20)*(100vw - 20rem)),2.5rem);El año pasado implemented this as a LightningCSS visitor, y hace que con viewports de 20rem o menos sea 1rem, aumente suavemente hasta 2.5rem en 60rem y luego se detenga, así que se siente bien porque responde también al tamaño de fuente del usuario sin necesidad de breakpoints
font-size-adjustfuncione así. El nombre confunde, pero entiendo quefont-sizecambia el tamaño de la caja em, mientras quefont-size-adjustcambia el tamaño del glifo dentro de esa caja emAsí que
emyremse mantienen igual, ychcambia. Perochya depende de la fuente de todos modos, así que tiene sentido que cambieOjalá escribieras sobre
font-size-adjust. No soy experto, así que no tengo mucha certeza, pero hasta ahora me parece algo casi desconocido que representa una mejora enorme. No puede hacer que dos fuentes cualesquiera coincidan automáticamente en todos los contextos, pero solo con igualar el tamaño de laxen vez de la caja em, creo que cubre el 90% de las fuentes/contextosLa intención del artículo es buena, y también importa la perspectiva de quienes no están totalmente metidos en HTML/CSS, pero muchas de las cosas “malas” pueden ser buenas según el contexto
Los selectores CSS son fáciles de abusar, pero no son intrínsecamente malos. En vez de concluir A o B, puedes tener reglas/selectores generales y, cuando haga falta, esparcir clases basadas en excepciones o clases utilitarias
Incluso dentro del artículo hay un buen ejemplo de selector:
Las media queries también pueden no hacer falta si se puede resolver con container queries
CSS puede sentirse enorme por toda su superficie, pero como se usa muchísimo y puede hacer tantas cosas, también hay choques de opinión frecuentes. Aun así, también hay que ver cuánto ha avanzado CSS y todo lo que se puede lograr con relativamente poco código una vez que asimilas los conceptos
Si quieres aprender más, https://every-layout.dev/ me ayudó bastante a entender cómo encajan entre sí distintos elementos en CSS
Empecé a entender el layout web cuando me di cuenta de que un buen sitio web, en esencia, tiene un diseño vertical. Los elementos deberían apilarse de forma natural uno arriba del otro, y conviene diseñar primero para pantallas móviles y luego desplegarlo para pantallas grandes como un extra
Me cuesta estar de acuerdo con esta afirmación. El anidamiento en CSS es solo azúcar sintáctico y no ayuda de forma significativa a evitar el problema de los selectores demasiado específicos.
Hace 15 años también usábamos mucho el anidamiento de selectores con Sass, y poco a poco todos llegamos a la misma conclusión: terminaba atando demasiado los selectores CSS a la estructura HTML y nos ponía trabas a nosotros mismos.
La trampa del anidamiento no se nota mucho al comienzo de un proyecto. En la etapa greenfield, cuando sobre todo estás creando funcionalidades nuevas, escribir CSS así parece una gran idea.
Pero unos meses después, cuando empiezas un cambio grande de layout y un rediseño, los elementos wrapper cambian de lugar en el HTML y adaptar el CSS a eso se siente como resolver un cubo de Rubik bajo los efectos del LSD.
Creo que el punto más alto en el manejo de la especificidad de selectores fue mantener casi todo en selectores simples, o sea, una sola clase, y usar solo unos pocos selectores compuestos y combinados como
a:hover. Eso sería la línea de BEM y OOCSS, y después la atención se movió rápidamente hacia herramientas centradas en JS.Es un artículo interesante, pero parece que el autor está usando los selectores anidados en un lugar donde no aportan ningún efecto.
&y que siempre debería usarse. Me parece una postura bastante razonable.Personalmente sigo dividido. Al principio pensé que era un error, pero cuando ya escribiste un montón de estilos y solo necesitas envolverlos con
header { … }para reducir el alcance, resulta bastante conveniente. También estaría bueno poder poner ahí dentro reglas at que no se basan en selectores, como@keyframes.Esto, sinceramente, es un consejo realmente malo. Me gusta lo que escribe Maklad, pero esto claramente parece escrito por alguien que nunca ha usado CSS de forma profesional.
Casi todo aquí son malas prácticas de aficionado que se evitan al escribir CSS de manera profesional.
Como se estiliza eso sin selectores, también se termina estilizando
<main>o<nav>sin selectores.En cambio, en un entorno profesional se dedica muy poco tiempo a diseñar cajas de contenido. Se hacen una vez al inicio del proyecto y luego, con suerte, solo se corrigen pequeños bugs de vez en cuando.
La mayor parte del tiempo se va en crear componentes personalizados o reutilizables. Los reutilizables son más difíciles y en la práctica terminas creando una especie de clon de Bootstrap específico para el sitio.
Los componentes personalizados son más fáciles, pero generan mucho código, y hace falta una estrategia para evitar que interfieran accidentalmente con otros componentes: BEM, OOCSS o clases utilitarias como las de Tailwind.
La conclusión es que cada técnica sirve para una escala distinta. Si la forma profesional de escribir CSS te parece inútil, probablemente es porque estás resolviendo un problema de otra escala.
Aun así, sí coincido con
Bad: Wrappers. He visto expertos en CSS escribir todo un sitio en uno o dos archivos, y también he visto gente que usa muchísimo CSS.Ese segundo camino suele terminar llevando a enfoques equivocados como BEM para poder gestionar tanta cantidad de CSS.
Parece haber consejos que se contradicen dentro del artículo.
Aparecen juntos
Good: Classless CSSyBad: CSS selectors, pero si usas CSS sin clases, en realidad tienes que depender más de los selectores CSS.Referencia: https://www.keithcirkel.co.uk/css-classes-considered-harmful/
Eso del vertical rhythm de “como si hubiera un cuaderno rayado invisible detrás de la página web” se puede lograr perfectamente usando valores EM.
Si mezclas distintas fuentes puede tambalearse un poco por la diferencia de métricas, pero incluso en ese caso puedes usar
align-items: baselinede flex.