Pantallas esqueleto: la UI espera con la forma de lo que va a llegar - #17
Merged
Conversation
La espera era la misma pokebola centrada en las dieciocho rutas, y de ahi salian las dos cosas que se ven mal. El salto: medida a Fast 3G la Pokedex espera en 1199px de alto y aterriza en 4257, 3058px que se abren de golpe bajo el cursor (movimientos +3025, habilidades +2699). Y la mezcla: con el hueco identico en todas, una rejilla, una tabla y una ficha esperaban con la misma forma y aparecian con tres distintas. skeletonHTML() reutiliza las clases reales del contenido que sustituye, asi que el hueco mide lo que va a medir el contenido sin repetir aqui ni un tamano. Cinco formas para las dieciocho rutas, una sola funcion: no hay donde puedan separarse. Sin temporizador en JS. El esqueleto entra en el DOM siempre -- reservar el hueco desde el primer frame es lo que quita el salto -- pero la animacion lo tiene invisible 200ms, asi que con los datos en cache el contenido lo sustituye antes de que llegue a verse y una espera corta ya no parpadea.
Cada ruta pide la forma de lo que va a pintar y, donde hay paginacion, le pasa su PAGE_SIZE en vez de un numero escrito otra vez aqui: la Pokedex son 50, los objetos 48, las habilidades 30. Es lo que hace que el hueco mida lo que va a medir el contenido sin que nadie tenga que acordarse de nada. Las de calculadora no cambian de forma -- el formulario ya se ve al instante y solo espera el panel de resultado -- asi que ahi el esqueleto es ese panel y no la pantalla entera. Con esto la pokebola centrada se queda sin llamantes: fuera ella, su CSS y sus 43 lineas de spinner. Las claves de i18n siguen vivas y ahora las dice el lector de pantalla, que con el esqueleto solo se quedaba sin nada que anunciar.
Las tres formas que no clavaban el alto, con el numero que dio medirlas: - La tabla de movimientos calculaba la fila desde el padding de .data-table td y salian 28px cuando la real mide 58,2 de minimo -- quien manda dentro no es el texto, es el badge de tipo. A 50 filas eso dejaba 1613px de salto. - El cuerpo de meta mide 1719px y esperaba con 408. - La ficha de un Pokemon mide 2073 y esperaba con 608. El bloque sube de 90 a 120px: la ficha con bloques bajos pedia 18 barras grises seguidas, que son mas ruido del que quitan, y a 120 son 14 y ademas se parecen a lo que va a haber ahi, que son tarjetas de seccion. La tabla es el unico hueco que no sale exacto y no puede salir: su fila no tiene alto fijo, va de 58,2 a 85,5 en la primera pagina y sube a 83,2 de media en la doce. Se ajusta a la primera, que es la unica que llega a ver el esqueleto -- el hueco lo pinta loadAll(), que corre una vez. Medido a Fast 3G, el salto al llegar los datos: Pokedex 3058 -> 0, habilidades 2699 -> 0, meta 1045 -> 0, objetos 748 -> 110, ficha 172, movimientos 3025 -> 474 y con esto ~10.
El esqueleto arregla el hueco, no lo que lo rellena. Medida a Fast 3G, la rejilla de la Pokedex se pinta con sus doce sprites visibles a cero cargados, y tardan 364ms mas en llegar: el sitio ya estaba reservado --.sprite es 96 o 128px fijos en CSS y ninguno empuja nada-- asi que no habia salto, pero si doce cuadros apareciendo de golpe sobre un hueco vacio. Un unico listener en captura y no un onload por <img>: `load` no burbujea, y los sprites se pintan desde ocho plantillas distintas que tendrian que acordarse cada una. El filtro es la ruta, que es lo que los define de verdad: todos salen de spriteUrl() o itemSprite() y viven bajo /sprites/. El estado por defecto es visible y no transparente a proposito. Si el listener no llega a dispararse, el sprite se ve sin animacion; al reves, un fallo aqui dejaria la Pokedex en blanco.
La ficha de un Pokemon no es una columna de bloques: es .bento, ocho secciones repartidas por column-count. El esqueleto pintaba una sola columna, asi que se veia bien hasta que llegaba el contenido y la pagina cambiaba de forma -- justo lo que esto venia a quitar. Ahora reutiliza .bento y .b, que es lo que hace que tenga las mismas columnas que la ficha en cada ancho sin repetir aqui un solo breakpoint. De paso, un fallo mio: la altura de seccion la puse como `.b .sk-block`, y las secciones que se rellenan solas dentro de la ficha (linea evolutiva, movimientos) pintan su esqueleto DENTRO de un .b -- esa regla les subia el bloque a 346px sin que nadie se lo pidiera. Va con clase propia. La linea evolutiva mide 527px y esperaba con 264. Con tres bloques en vez de dos, y el resto ya medido, el salto de la ficha entera se va a 0: medido a Fast 3G en Pikachu y en Mewtwo, que no tiene cria.
Por debajo de 1000px column-count vuelve a 1 y las ocho secciones se apilan en vez de repartirse: la ficha entera pasa a medir 4751px. El hueco seguia calculado para dos columnas y se quedaba en 3486. Con 425 por seccion sube a 4039, medidos los dos a 380 de ancho.
✅ Deploy Preview for fluffy-pasca-8ba512 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Las pantallas cambiaban de tamaño al cargar y cada una esperaba distinta. La causa era una sola: las dieciocho rutas esperaban con la misma pokébola centrada dentro de 60px de padding, así que el hueco no medía nada parecido a lo que iba a ocupar el contenido, y una rejilla, una tabla y una ficha esperaban las tres igual para aparecer luego con tres formas distintas.
Ahora cada ruta espera con un esqueleto que tiene la forma y el alto de lo que va a pintar.
Lo que se midió
En local todo carga instantáneo y no reproduce nada, así que todo esto está medido con red lenta simulada (Fast 3G: 1,6 Mbps, 150 ms de latencia, CPU ×4). Antes, el spinner estaba en pantalla entre 0,7 y 3,5 segundos según la ruta.
Salto de altura al llegar los datos, antes y después:
#/pokedex#/moves#/abilities#/meta#/items#/pokedex/<id>#/counter#/survive#/speed#/compare#/team#/eggVerificado también en tema claro (Pokédex 0, movimientos 74, ficha 40) y a 380px de ancho (Pokédex +156). Sin desbordes horizontales en ninguna.
Cómo está hecho
skeletonHTML()enjs/ui.jses la única función, con seis formas para las dieciocho rutas:grid,tiles,cards,table,blocksydetail. No hay un esqueleto por pantalla, así que no hay donde puedan separarse.El esqueleto reutiliza las clases reales del contenido que sustituye —
.pokemon-gridcon.pokemon-card,.items-grid,.data-table, y el.bentode la ficha. Esa es la propiedad que importa a un año vista: el hueco mide lo que va a medir el contenido sin repetir aquí ni un tamaño, y cambiar el alto de una tarjeta mueve su esqueleto solo. Donde hay paginación, cada ruta pasa su propioPAGE_SIZE(50 la Pokédex, 48 objetos, 30 habilidades).Sin temporizador en JS. El esqueleto entra en el DOM siempre, porque reservar el hueco desde el primer frame es justo lo que quita el salto, pero la animación lo tiene invisible 200 ms: con los datos en caché el contenido lo sustituye antes de que llegue a verse, y una espera corta ya no parpadea en gris.
Los sprites entran en vez de aparecer de golpe. Medido: la rejilla se pinta con sus doce sprites visibles a cero cargados y tardan 364 ms más en llegar. No era un problema de layout (el hueco ya estaba reservado,
.spriteson 96/128px fijos), sino el golpe. Un solo listener en captura filtrando por/sprites/, y el estado por defecto es visible: si no llega a dispararse, el sprite se ve sin animación en vez de quedarse en blanco.La pokébola se queda sin llamantes y se va con sus 43 líneas de CSS. Las claves de i18n siguen vivas y ahora las anuncia el lector de pantalla, que con el esqueleto solo se quedaba sin nada que decir.
Lo que no llega a cero, y por qué
loadAll(), que corre una vez).Verificación
npm run check: los 26 checks en verde.npm run build: OK, 53 módulos, CSS con las clases nuevas.