astrotailwindalpine.jsfrontendreflexió

D'HTML pla a frontend modern: el que vaig aprendre pel camí

Una reflexió personal sobre migrar un projecte d'HTML/CSS/JS vanilla a Astro, Tailwind CSS i Alpine.js — què va motivar cada decisió i què va canviar després.

D’HTML pla a frontend modern: el que vaig aprendre pel camí

Fa un temps vaig agafar el lloc web d’un gimnàs de powerlifting, RZ Powerhouse. Va començar com un projecte petit: construir el lloc en HTML i CSS, afegir una mica de JavaScript per als elements interactius, i prou. No era el meu stack habitual — vinc del backend — però no era res que no pogués fer.

El problema va arribar més tard, quan el lloc continuava creixent.


El moment en què el codi deixa d’ajudar-te

Hi ha un punt en tot projecte frontend vanilla on obres el fitxer principal i no saps realment per on començar. No perquè el codi sigui dolent. És que ha crescut sense estructura, i cada petit canvi requereix entendre massa context.

Per a mi aquell moment va arribar quan el gimnàs volia afegir pàgines individuals per a cada un dels seus serveis. Em vaig adonar que hauria de duplicar gairebé tot l’HTML, mantenir el CSS sincronitzat en múltiples llocs i copiar blocs de JavaScript d’un fitxer a un altre. Abans d’escriure una sola línia nova, ja sabia que el que estava a punt de fer seria un problema més endavant.

És el moment en què val la pena aturar-se i repensar l’arquitectura.


Per què Astro

Feia temps que sentia parlar d’Astro però mentalment l’havia posat a la carpeta de “una altra cosa de frontend per aprendre”. El que em va fer canviar d’opinió va ser entendre la seva proposta concreta: genera HTML estàtic per defecte i només envia JavaScript al navegador quan és realment necessari. Sense bundles inflats. Sense configuració complexa. La sortida per defecte ja és ràpida.

Per a un lloc com el del gimnàs — contingut majoritàriament estàtic, amb alguns punts interactius — era exactament el que necessitava.

El que més em va sorprendre quan vaig començar va ser com es nota de natural la componentització. Agafes cada secció de l’HTML monolític i la converteixes en el seu propi fitxer .astro. De cop pots raona sobre la navbar sense veure el codi del footer. Pots tocar la secció de testimonis sense tenir por de trencar el formulari de contacte.

El canvi que em va estalviar més feina va ser poder crear un sol layout per a les pàgines de serveis. El gimnàs té sis serveis diferents, i amb una sola plantilla ben definida, totes les pàgines es generen des del mateix lloc. Canvies el disseny una vegada i tot s’actualitza.


Per què Tailwind CSS

Tailwind va ser la decisió sobre la qual vaig dubtar més. Escriure classes a l’HTML en lloc de en un fitxer CSS separat em semblava un pas enrere.

El que em va convèncer va ser ser honest sobre el problema real que tenia. El styles.css que havia anat construint no era fàcil de mantenir perquè era un fitxer global que afectava tot. Per canviar el color d’un botó havia d’assegurar-me que no hi havia deu altres llocs que depenguessin d’aquella mateixa classe.

Amb Tailwind els estils de cada element estan just al costat de l’element. Quan obro el component navbar, veig exactament quins estils té aquella navbar. Sense buscar en un altre fitxer. Sense efectes secundaris inesperats.

El que no esperava és que també t’allibera del problema del naming. Posar bons noms a les classes CSS és sorprenentment difícil. És card--featured o card-featured o featured-card? Segueixo BEM o no? Amb Tailwind aquest problema desapareix perquè les classes ja tenen nom: són les utilitats de la biblioteca.


Per què Alpine.js

El JavaScript del projecte original era el que més em costava replantejar. Funcionava. Els efectes interactius estaven ben fets. Però hi havia alguna cosa que em molestava: l’estat de cada component vivia en variables soltes del mòdul, i el DOM era l’única font de veritat real sobre el que s’estava mostrant.

Quan vaig necessitar afegir interactivitat nova — un carrusel d’imatges amb arrossegament tàctil, un formulari que mostra un toast de confirmació — em vaig trobar escrivint cada cop més codi per sincronitzar l’estat amb el DOM. El resultat era correcte però difícil de seguir.

Alpine.js va resoldre això d’una manera que em va semblar molt natural: defineixes l’estat del component al propi HTML, i la biblioteca s’encarrega de mantenir el DOM sincronitzat. Sense querySelector. Sense classList.toggle. Canvies un valor i la pantalla s’actualitza sola.

El que més m’agrada és que Alpine no necessita el seu propi pas de build. S’integra a Astro amb un parell de línies de configuració i funciona. Per a interactivitat lleugera — menús, sliders, formularis — és més que suficient i no afegeix complexitat innecessària al projecte.


Què va canviar després de la migració

Tècnicament el lloc va millorar: carrega més ràpid, les imatges s’optimitzen automàticament, el SEO està millor estructurat. Però no és el que noto dia a dia.

El que més va canviar va ser la confiança per tocar el codi. Quan el client demana un canvi en la pàgina d’un servei, sé exactament quin fitxer obrir i el que pot veure’s afectat. No hi ha un fitxer CSS de 27 KB que tingui por d’editar. No hi ha un bloc de JavaScript del qual no sé ben bé d’on ve.

Aquella sensació — poder fer un canvi sense estar pensant tot el rato en el que podries estar trencant — és el que més valoro del procés. No era una qüestió de tecnologia moderna per gust de ser-ho. Era una qüestió de poder treballar còmodament en el projecte a llarg termini.


El que vaig aprendre sobre assets i imatges

Migrar el framework va ser el més visible, però hi havia una altra àrea on vaig cometre errors durant força temps: els assets. Imatges, vídeos, icones — coses que semblen trivials fins que et preguntes per què el lloc carrega lent o per què les imatges es veuen borroses en pantalles retina.

Formats d’imatge

La regla que vaig interioritzar: les imatges fotogràfiques van en .webp, i si vols exprimir més rendiment, també en .avif. WebP ofereix entre un 25 i un 35% d’estalvi respecte a JPEG amb qualitat visual equivalent, amb suport en més del 96% dels navegadors. AVIF va un pas més lluny — pot arribar al 50% menys de pes — però és més lent de codificar i té un suport lleugerament menor (tot i que ja supera el 93%).

La forma correcta de servir-los és amb l’element <picture>:

<picture>
  <source srcset="imatge.avif" type="image/avif">
  <source srcset="imatge.webp" type="image/webp">
  <img src="imatge.jpg" alt="descripció">
</picture>

El navegador tria el millor format que suporta. Astro fa això automàticament amb el seu component <Image />.

Una cosa important: els originals (JPG, PNG) cal conservar-los al repositori encara que no es serveixin en producció. WebP i AVIF són formats amb pèrdua — si generes WebP a partir d’un altre WebP, degrades la qualitat progressivament. Els originals són la font de veritat per regenerar en el futur.

Dimensions

Per a imatges a pantalla completa, 1920px d’amplada és més que suficient per a la majoria de monitors. Per a thumbnails o previsualitzacions en galeries, un màxim de 500px d’alçada és un bon criteri. Sempre cal mantenir la relació d’aspecte original — forçar unes dimensions diferents distorsiona la imatge.

Nomenclatura

Els fitxers d’assets segueixen la convenció kebab-case: la-meva-imatge.webp, no LaMevaImatge.webp ni la_meva_imatge.webp. Les URLs són case-sensitive en servidors Linux i el guió és més llegible que el guió baix.

SVGs

Les icones i logotips van en .svg. Són vectorials — es defineixen amb coordenades matemàtiques, no píxels — de manera que escalen perfectament a qualsevol mida sense perdre qualitat. No serveixen per a fotografies, però per a icones, logotips i il·lustracions geomètriques són l’opció correcta. Inclosos inline a l’HTML permeten controlar el color amb CSS.

Vídeos

Si el projecte inclou vídeo, l’estàndard és oferir dues fonts: .mp4 (H.264) per compatibilitat àmplia, i .webm (VP9 o AV1) per millor compressió en navegadors moderns.

Animacions i Tailwind

Un matís que vaig trigar a entendre: Tailwind és un framework d’utilitats CSS, no una biblioteca d’animacions. Té unes poques classes predefinides (animate-spin, animate-pulse, animate-bounce) que cobreixen casos bàsics, però per a animacions personalitzades l’eina és @keyframes de CSS directament. Per a animacions controlades des de JavaScript, hi entren biblioteques específiques com GSAP o Motion.


Quan té sentit aquest camí

No tots els projectes necessiten aquesta migració. Si tens una landing de tres seccions que no creixerà, l’HTML pla és perfectament vàlid i molt més simple.

El senyal que val la pena considerar-ho és quan comences a tenir por del teu propi codi. Quan duplicar una pàgina en lloc d’abstraure-la sembla l’opció més segura. Quan canviar el CSS d’un component implica buscar en tot el fitxer per veure el que pot trencar-se.

En aquell punt, eines com Astro, Tailwind i Alpine no són complexitat afegida. Són la manera de recuperar el control.