Constelación de Palabras (IV): un id que no era el que tocaba, y por qué comparar ya no significa “más pequeño”
Esta entrada continúa las tres anteriores sobre Constelación de Palabras. Esta vez el punto de partida no fue una idea nueva, sino un aviso de uso real, con dos capturas de pantalla: “las imágenes tienen que ser pelín más pequeñas porque no caben… y no caben todas las palabras”. La vista de “Comparar los dos modos”, que había llegado en la sesión anterior, se salía de la ventana del navegador y cortaba palabras por los bordes de cada constelación.
La primera sospecha, razonable y equivocada a medias
El diagnóstico inicial fue de manual de CSS Grid: la vista de comparación coloca “Resumen” y “Evocación” en dos columnas con display: grid; grid-template-columns: 1fr 1fr, y cada constelación es un <svg> con width y height fijados como atributo — puestos ahí a propósito en la sesión anterior, para que la descarga de imagen saliera a tamaño completo. Esa combinación tiene una trampa conocida: por defecto, una celda de rejilla no se encoge por debajo del tamaño intrínseco de lo que contiene (min-width: auto), así que un <svg> de 1000×700 puede forzar su columna a ser más ancha de lo que le corresponde. Se aplicó el arreglo de libro, min-width: 0 en la celda, y de paso se ajustaron algunos tamaños máximos por si acaso.
Ese arreglo no estaba mal, y se ha dejado en el código porque no hace daño. Pero al comprobarlo de verdad con un navegador sin cabeza (Playwright), midiendo con getBoundingClientRect() en vez de fiarse del ojo, el recuadro de cada constelación seguía saliendo casi del doble de alto de lo que le correspondía a su ancho. min-width: 0 no era la causa principal. Quedaba algo más por encontrar.
La causa real: una regla que nunca llegaba donde tenía que llegar
Revisando la hoja de estilos con lupa, la explicación estaba en una sola línea, escrita hace dos sesiones y nunca vuelta a mirar:
#lienzo {
width: 100%;
height: auto;
}
Esa regla decide que el lienzo ocupe el ancho de su recuadro y que el alto se ajuste en proporción. El problema es el selector: #lienzo es un identificador, y un identificador solo puede pertenecer a un elemento de toda la página. La vista individual usa id="lienzo", así que la regla le llegaba perfectamente. Pero la vista de comparación, al necesitar dos lienzos a la vez, los llama id="lienzo-resumen" y id="lienzo-evocacion" — dos identificadores distintos que esa regla, escrita por identificador, no tocaba nunca. Sin ninguna regla de tamaño que la alcanzara, cada uno de esos dos <svg> se dibujaba con el tamaño de sus propios atributos width="1000" height="700": mil por setecientos píxeles reales, muchísimo más grande que el recuadro donde debía encajar, y recortado sin piedad por el overflow: hidden del recuadro — de ahí las palabras cortadas por los bordes, y de ahí que la imagen entera no cupiera en la pantalla.
Es el tipo de fallo que no se ve leyendo el código una vez, ni siquiera revisándolo con calma: la regla existe, está bien escrita, y funciona — para un elemento. Solo se nota cuando hay dos elementos que deberían compartirla y no la comparten. El arreglo fue cambiar el identificador por una clase compartida (class="lienzo" en los tres <svg>, y .lienzo en vez de #lienzo en la hoja de estilos), para que la misma regla llegue a los tres lienzos por igual, sean uno o sean varios.
De paso, con la altura ya bien resuelta, se ajustó también cómo se fija la proporción: en vez de dejar que cada <svg> calculara su alto a partir de su propio ancho (que es justo donde el <svg> puede comportarse de forma confusa dentro de una rejilla), la proporción 1000:700 se fija ahora en el propio recuadro contenedor con la propiedad aspect-ratio, y el lienzo simplemente ocupa el 100% de ese recuadro ya bien dimensionado. Es un paso más de seguridad, no el arreglo principal — pero conviene que la proporción no dependa de un cálculo ambiguo si puede fijarse directamente.
Las etiquetas que se salían por los bordes
La segunda mitad del aviso — “no caben todas las palabras” — tenía una causa distinta y más pequeña. Las etiquetas de cada estrella se centran sobre su punto (text-anchor: middle), lo cual funciona bien salvo cuando el punto cae cerca de un borde del lienzo: entonces la mitad de la palabra que se extiende hacia ese lado sale del dibujo y queda recortada por el mismo overflow: hidden de antes. Con constelaciones ya bien dimensionadas esto se nota menos, pero seguía pudiendo pasar con palabras largas o de varias palabras (habituales en el modo evocación) cerca de un extremo.
La solución fue anclar la etiqueta de otra forma cuando el punto está cerca de un borde: si está cerca del izquierdo, la etiqueta crece hacia la derecha (text-anchor: start); si está cerca del derecho, crece hacia la izquierda (text-anchor: end); en el resto de casos, se queda centrada como siempre. Hay que fijarlo como estilo en línea (elemento.style.textAnchor, no como atributo suelto), porque si no la regla de la clase .etiqueta-estrella en la hoja de estilos, más específica, lo pisaría sin avisar.
El cambio de aspecto que no estaba en el diagnóstico técnico
Con el <svg> ya bien dimensionado, la vista de comparación cabía perfectamente en la ventana — pero perfectamente pequeña: dos columnas significan que cada constelación tiene, como mucho, la mitad del ancho disponible. Se comprobó y funcionaba, sin ningún error, y aun así llegó un segundo aviso: “mejor poner las dos grandes una encima de otra, es que ahora son muy pequeñas y salen muy pocas palabras”. No era un fallo — la vista cabía y no recortaba nada —, era que la solución correcta al problema técnico no era la solución correcta para leerlo con comodidad.
El cambio fue sencillo una vez señalado: quitar la regla que ponía las dos columnas a partir de cierto ancho de ventana y dejar la rejilla siempre en una sola columna. “Resumen” y “Evocación” se apilan ahora una debajo de la otra, cada una al mismo tamaño que tenía la vista individual de siempre — nada de encogerlas para que quepan las dos a la vez. Cuesta un poco más de scroll vertical, y a cambio cada constelación se lee tan bien como si se hubiera generado sola.
Cómo se comprobó
Ningún cambio de esta sesión tocó layout.py, ia.py ni main.py — las veintiséis pruebas automáticas de siempre pasan exactamente igual, porque no había nada de lógica de negocio que arreglar, todo era CSS y JavaScript de la página. La comprobación, por tanto, fue enteramente con un navegador real (Playwright, sin cabeza): generar la vista de comparación con datos simulados y medir con getBoundingClientRect() — no solo mirar una captura — que la página no se desborda horizontalmente, que el recuadro de cada constelación mide lo que le corresponde a su ancho real, y que cada etiqueta, incluidas las de dos palabras cerca de los bordes, queda dentro de los límites de su propio lienzo. Se repitió la misma comprobación después de pasar a una sola columna, y otra vez la descarga de imagen en los tres botones (individual, resumen, evocación), para confirmar que sigue produciendo un PNG válido y a tamaño completo con el nuevo diseño.
Qué no hace todavía (límites honestos)
- El arreglo de
min-width: 0en la celda de la rejilla se ha dejado puesto por higiene, aunque el diagnóstico final mostró que no era la causa principal del problema — no está de más, pero conviene no repetir la lección al revés: comprobar con medidas reales antes de dar un arreglo por bueno, aunque sea el que “toca” según el manual. - Las etiquetas cercanas a un borde se anclan a un lado en vez de centrarse, lo cual evita el recorte pero hace que su posición relativa al punto ya no sea exactamente igual en todos los casos — un detalle menor, y preferible con claridad a perder parte de la palabra.
- La vista de comparación en una sola columna significa más scroll vertical en pantallas pequeñas. Si en algún momento hiciera falta un término medio, la vía más sencilla sería ofrecer las dos formas y dejar elegir, no volver a encoger las dos columnas por defecto.
Siguiente paso
Que José Luis vuelva a probar “Comparar los dos modos” con textos reales de clase, ahora que cada constelación se lee a tamaño completo, y compruebe si el scroll vertical resulta cómodo o si conviene revisarlo con pantallas más pequeñas, como una tablet en el aula. Y, como lección para la próxima vez que aparezca un fallo parecido: cuando una regla CSS por identificador solo cubre “el de siempre” y aparece una segunda copia de ese mismo elemento, conviene sospechar del selector antes que del diseño — es un error fácil de cometer y fácil de no ver, precisamente porque el código de partida funcionaba bien.


Etiqueta:AIDARAC, constelación de palabras, css, depuración, ies monterroso, montesteam, playwright, ROCKY, svg


