- Rol «externas» para la asamblea de externas: pide sin cupo, siempre con el colectivo de fuera y su contacto, y sus solicitudes salen en naranja hasta que la asamblea de la Enre las confirma. - /pedir/ explica en una línea que los colectivos externos piden fecha en la asamblea de externas, los lunes de 19:00 a 20:00. - Seguridad: argon2 limitado a dos cálculos a la vez y el intento se cuenta antes de calcular (60 accesos simultáneos llevaban el proceso a 3,8 GB); bloqueo por cuenta a 20 fallos para que no se pueda dejar fuera a la asamblea; avisos por sesión en vez de por URL; sig sin «..»; eventos de 31 días como mucho; parámetros de argon2 acotados. - Títulos pegados arriba en todas las páginas; la franja de la enredadera recupera ese alto para seguir llenando la pantalla. - despliegue/: instalar.sh, cuenta.sh, servicio de systemd con el proceso encerrado, fragmento de nginx que además deja de servir .git y las notas internas, y configuración de ejemplo. Ninguna contraseña en el repositorio. |
||
|---|---|---|
| despliegue | ||
| fuentes | ||
| gestor | ||
| INFO | ||
| subdir | ||
| .gitignore | ||
| 404.html | ||
| calendario.html | ||
| code-462w-pink.zip | ||
| Code462WPink-Regular.ttf | ||
| code_.png | ||
| colectivos.html | ||
| context.txt | ||
| eventos.html | ||
| favicon.ico | ||
| favicon.svg | ||
| index.css | ||
| index.html | ||
| info.txt | ||
| panel.html | ||
| README.md | ||
| tatus.html | ||
Web del CSO La Enredadera de Tetuán
Sitio estático: HTML y CSS. No hay build, ni framework, ni dependencias. Se despliega copiando la carpeta y sirviéndola con cualquier servidor web.
Todo el JavaScript que hay son los dos calendarios, que venían de antes y
funcionan. La navegación, el menú, las fichas de colectivo y el brote de REDES
son CSS puro: funcionan con JavaScript desactivado. Comprobado, no
supuesto: se desactiva el JS por CDP y se mira. Los dos calendarios, que sí lo
necesitan, avisan de ello con un <noscript> y dicen dónde mirar.
Ver la web en local
python3 -m http.server 8099 --bind 127.0.0.1
y abrir http://127.0.0.1:8099/. Tiene que servirse por HTTP: si abres el
fichero con file:// fallan las rutas absolutas y el calendario de convoca.la.
Los ficheros
| Fichero | Qué es |
|---|---|
index.html |
Portada: la enredadera con seis hojas |
colectivos.html |
Las doce hojas de colectivos: once con ficha y Tattoo Circus, que lleva a su micrositio |
calendario.html |
Horarios semanales de cada colectivo |
eventos.html |
Agenda de convoca.la |
subdir/campa.html |
Campañas |
subdir/sobre_nosotrxs.html |
Quiénes somos y la historia del espacio |
subdir/contacto.html |
Dónde estamos y cómo proponer algo |
tatus.html, panel.html |
Tattoo Circus: micrositio aparte, con su propio CSS |
404.html |
Página de error, con el mismo armazón que el resto |
index.css |
Todo el estilo del sitio, menos los dos del Tattoo Circus |
INFO/ |
Imágenes. 12 de las 18 no se usan (3,2 MB): ver pendientes |
favicon.svg, favicon.ico |
Icono: una hoja verde con los nervios en rosa |
Code462WPink-Regular.ttf |
La fuente de los títulos, servida desde aquí |
Añadir una hoja a la enredadera
Copia un <li> entero y cambia el enlace y el texto. Nada más. La
posición, el ángulo y el tamaño salen solos de :nth-child, así que la hoja
nueva se coloca en el punto que le toca sin tocar el CSS.
<li>
<a class="hoja" href="/donde-va.html">
<svg class="hoja-svg" viewBox="0 0 100 114" aria-hidden="true"><use href="#hoja-forma"></use></svg>
<span class="hoja-txt">Como se llama</span>
</a>
</li>
Variantes:
class="hoja brota"— hoja más tenue, para un colectivo que existe pero todavía no ha escrito su ficha.- Para que abra una ficha en vez de ir a otra página, el enlace apunta a
#ficha-loqueseay añades el<article class="ficha" id="ficha-loquesea">al final del documento, copiando uno de los que ya hay.
Aviso: los ciclos son de 6. Si añades una séptima hoja a la portada, la raíz seguirá pasando por su sitio, pero repasa a ojo que no se pise con la vecina — y pasa el banco de pruebas (más abajo).
Los colores
Están todos en :root, al principio de index.css. Para recolorear el
sitio entero solo hay que tocar ahí.
| Variable | Para qué |
|---|---|
--verde, --verde-hondo, --verde-humo |
fondos |
--rosa |
contorno de las hojas y acentos. Nunca para texto normal: da 3.1:1 |
--rosa-legible |
el rosa para textos y enlaces: 6.3:1 |
--verde-vivo |
nervios y zarcillos. Es adorno: 1.7:1, no vale para texto |
--verde-hoja |
el verde legible, para subtítulos |
--tinta, --tinta-suave |
textos |
--marron, --negro |
las dos hebras de la raíz |
Los contrastes están medidos contra WCAG AA. Si cambias un color, mídelo: hay
un cálculo hecho en ../BITACORA.md que puedes reutilizar.
Las tres medidas de la enredadera
Están en .enredadera, y son tres cosas distintas a propósito. Antes eran
una sola variable y se estorbaban entre sí.
| Variable | Qué manda |
|---|---|
--fila |
la separación: alto de la franja. Más alta = hojas más apartadas y menos hueco abajo |
--hoja-base |
el tamaño de la hoja |
--col |
el ancho real de columna, que es el tope de la hoja |
Por qué separadas: estirar la franja para que llene la pantalla agrandaba
también las hojas y volvía a juntarlas. Ese fue el callejón de «--fila a
63vh», anotado en ../BITACORA.md.
Y --col no es 15vw: coinciden solo por debajo de 1680px. A partir de ahí
la rejilla deja de crecer (max-width:1680px) pero 15vw sigue subiendo, así
que a 1920 las hojas se salían de su columna y se pisaban.
En móvil mandan otras dos, en .enredadera-wrap:
--ancho-hoja, de la que salen a la vez el ancho de la hoja y el hueco bajo la cabecera, porque las hojas de móvil giran hacia arriba y sobresalen ~0.96 de su ancho por encima de donde se agarran. Si se separan esas dos medidas, la primera hoja se come el subtítulo. Va contra las dos dimensiones —min(28vw, 13.6vh)—: sólo convw, en una pantalla baja las seis hojas no entran sin deslizar.--celda, el alto de cada<li>. Es más corto que la hoja a propósito: las hojas alternan lado, así que se entrelazan como en una enredadera de verdad. Reparte entre las seis lo que queda tras la cabecera, el hueco de entrada y lo que la última asoma por abajo, así que la portada entra sin deslizar de 320x568 para arriba.
El tallo de móvil son tres dibujos, no uno: la onda que empieza a la
derecha, su espejo y el remate con espiral de la última celda. La onda es
x = 50 ± 28·cos(pi·y/100) en un recuadro de 100x100 que se pinta cuadrado
—background-size:var(--celda) 100%—, así que la escala sale uniforme. En los
dos bordes la tangente es vertical: por eso dos celdas seguidas empalman sin
junta, y por eso los extremos caen justo donde se agarra la hoja. Si tocas la
amplitud, toca también el --centrar de las hojas, que vale AM/100.
Cuidado con --tam dentro de una hoja
Las reglas por hoja son de la forma:
.enredadera > li:nth-child(12n+4) .hoja{ --giro:154deg; --tam:0.92; }
Ese .hoja es un descendiente, así que alcanza también a las hojas que
haya dentro del <li> —los brotes de REDES— y con especificidad (0,3,1), que
le gana a cualquier .una-clase. Poner --tam en .hoja-brote no hacía
nada: los brotes salían con el --tam de REDES, al doble de tamaño, y se
comían a las hojas vecinas.
Regla: dentro de un <li> de la enredadera, no confíes en --tam. Si
necesitas un tamaño propio, escríbelo en la medida, sin var(--tam).
La raíz (los dibujos de la enredadera)
Los dibujos —la bajada desde el título, la franja de ordenador, su remate y el tallo de móvil— no están escritos a mano: los genera un script, porque el trenzado hay que calcularlo (la perpendicular a lo largo del recorrido).
cd ../prueba && python3 raiz2.py # regenera raiz2.json
Después hay que reinyectar los SVG en el CSS. Y lo más importante:
Los puntos por donde pasa la raíz y las alturas de las que cuelgan las hojas (
--yen las reglasnth-child(12n+N)) tienen que coincidir. Si mueves uno sin mover el otro, las hojas quedan flotando sin tocar la raíz.
Para eso está ../coherencia.py: compara el CSS contra el JSON y avisa.
Pásalo siempre después de tocar la raíz.
La franja de ordenador: dos filas, no una
La franja es la única parte que se repite, porque una página puede tener más hojas de las que caben en una fila: colectivos tiene doce, o sea dos.
El dibujo lleva dos filas: la pasada de izquierda a derecha y, debajo, esa
misma pasada en espejo —un <use> del mismo grupo, así que no pesa el
doble—. Entra y sale vertical por las dos esquinas, de modo que empalma
con su espejo por la derecha y con la copia siguiente por la izquierda. Puesto
con repeat-y y background-size:100% calc(var(--fila) * 2), la enredadera
serpentea por las filas que haga falta sin una sola junta. Antes el dibujo
era de una fila y remataba en espiral: en colectivos se veían dos ramas
sueltas, la segunda empezando otra vez desde el margen izquierdo.
De ahí salen tres cosas encadenadas:
- La tanda de las reglas por hoja es de doce (
nth-child(12n+N)), no de seis: las seis de la pasada y las seis del espejo, que son las mismas leídas del revés y con el giro cambiado de signo.../coherencia.pylo comprueba. - El tallo va en dos capas, no en el fondo del
<ul>:.enredadera::beforepinta todas las filas menos la última (top:0; bottom:var(--fila)) y.enredadera::afterpinta la última con el remate en espiral. Las dos conz-index:-1, que es donde estaba el fondo al que sustituyen. - Si la última fila es par, la pasada va de derecha a izquierda y el remate
se pinta en espejo. Lo decide un
:has()sobre dónde cae el último<li>dentro de la tanda de doce, así que añadir una hoja sigue sin tocar nada.
La bajada del título
Es el dibujo más delicado de los tres, porque empalma con dos cosas a la vez: el título por arriba y la franja por la esquina de abajo a la izquierda.
- Su viewBox es 1000x72 y la caja que lo pinta mide
--bajada, o sea el 7.2% de--rejilla. Los dos números van juntos: si cambias uno, cambia el otro, o el dibujo se deforma —preserveAspectRatioesnone—. - Las hebras no son
strokesino cintas rellenas de grosor variable (../prueba/cinta.py), afiladas en la punta y del grosor de la franja —9 y 5.5— en el empalme. Si tocas el grosor de la franja, toca también ése. - El recorrido llega vertical al margen izquierdo: es lo que evita el pico contra la franja. No lo hagas terminar en diagonal.
--filadescuenta--bajadapor su nombre. No vuelvas a meterla en una constante fija: la bajada mide en proporción al ancho, no envh.
El brote de REDES
Al pulsar REDES salen tres hojas pequeñas, una por red. Cuelgan de un tallo
de verdad, no flotan: cada <li> del brote lleva un ::before que es su
trozo de tallo, y los tres se encadenan —el primero va hasta el agarre en la
enredadera, el segundo hasta el primero y el tercero hasta el segundo—, así que
lo que se dibuja es un solo brote con tres hojas, no tres hojas sueltas.
Dos cifras por hoja bastan, y son las mismas que la colocan leídas del revés:
.brotes > li:nth-child(2){ --largo:0.605; --ang:262.4deg; }
--largova en unidades de--ry--anges absoluto, porque el<li>no gira (gira la hoja que lleva dentro).- Por eso lo que se coloca es la punta del rabillo —
translate(-50%,0), no(-50%,-50%)—: si se colocara el centro de la hoja, el punto donde empieza el tallo dependería de lo que mida la hoja, que va envw, y el ángulo no podría ser una constante. - Si mueves un nudo, recalcula las dos:
--largoes la distancia al nudo anterior y--ang=atan2(dx, -dy).
En ordenador el brote sale hacia abajo y a la izquierda, al hueco que dejan Eventos y Campañas. En móvil no cabe un abanico: el tallo es vertical y las hojas ocupan los ~130px del centro, así que lo único libre son las franjas de los lados —62px a 390, 86 a 360, 110 a 320—. Ahí el brote sale por la izquierda, pasa por debajo de la hoja de REDES y trepa por el margen. Antes salía a la derecha y se comía Eventos y Campañas.
El banco de pruebas
cd ..
python3 coherencia.py # raíz y hojas cuadran
python3 qa.py --breve # las 10 páginas en 15 pantallas
python3 qa.py index.html # una sola, con detalle
Puntuación 0 = perfecto. Mide, en cada página y cada tamaño de pantalla:
- desborde horizontal
- si la portada entra sin deslizar en ordenador
- hojas cortadas por los bordes
- hojas que se pisan entre sí
- etiquetas que se solapan
- los brotes de REDES: que no se salgan, no pisen a las hojas, no se toquen entre ellos y no partan su etiqueta en dos líneas
- contraste de todos los textos contra su fondo real, con el umbral de
WCAG AA (4.5, o 3.0 si la letra es grande). Ojo: las fuentes usan
clamp()convw, así que un titular puede ser «grande» en ordenador y dejar de serlo en móvil — por eso se mide en las quince pantallas y no en una - contenido perdido dentro de elementos con
overflowoculto - foco fantasma: enlaces que se tabulan pero no se ven
- espacio muerto en los bordes
- el menú desplegado: que se alcancen todos los enlaces
El banco va por CDP, y no es un capricho
chromium --dump-dom y --screenshot sujetan la ventana a un mínimo de
~500px: si pides 320, maqueta a 500. La captura encima engaña, porque
reescala la imagen al ancho pedido y parece buena. Da igual --headless,
--headless=new o --headless=old.
Durante un tiempo el banco midió así, y las cuatro pantallas de móvil (430,
390, 360 y 320) daban todas la medida de 500: el 28% de cada barrido era
falso. Por eso cdp.py levanta chromium con --remote-debugging-port y fija
el viewport con Emulation.setDeviceMetricsOverride, que sí respeta cualquier
ancho. Hace falta --remote-allow-origins=* o el websocket devuelve 403.
No vuelvas a medir con --dump-dom. Si un día das con números idénticos
en varios anchos distintos, eso es la señal: el ancho no está cambiando.
Al medir cosas que se animan (los brotes, el menú) hay que quitar la
transición antes, o se mide a medio camino. Y --r y las demás variables
con calc() no se pueden leer con getPropertyValue: devuelven el texto. Se
miden creando un testigo con width:var(--r).
Recorrer el foco
python3 teclado.py # se usa desde otro script: ver el ejemplo al final
Pulsa Tab de verdad por CDP y anota cada parada. Mover activeElement con
.focus() no vale: no prueba el orden de tabulación ni lo que el navegador se
salta. Va aparte del banco porque cada parada es una ida y vuelta al
navegador y en las 98 mediciones sería eterno.
Cuidado: la sonda se recorta
SONDA_JS no es el texto entero de la sonda: se recorta desde la línea
var d=document.documentElement hasta donde escribía su resultado. Todo lo
que se ponga fuera de ese trozo desaparece sin avisar. Pasó con el apagado
de animaciones: estuvo seis vueltas escrito y sin aplicarse. Al tocar la sonda,
comprobar que lo nuevo está de verdad:
python3 -c "import qa; print('sinAnim' in qa.SONDA_JS)"
La sonda apaga las animaciones
Lo primero que hace es meter *{animation:none!important}. La portada tiene
una entrada animada que acaba a los 0.8s y la sonda mide a los 1.1s: medir tan
cerca del final es pedir problemas. Como la animación termina en el estado
normal, apagarla deja justo lo que hay que medir.
Cuidado al medir cosas que se abren
La barra lateral cierra con transition: visibility 0s .32s. Si un bloque de
la sonda la abre y la cierra, todo lo que se mida después la ve todavía
abierta. Ha mordido tres veces: al foco, a los brotes y al contraste. Por
eso el bloque del menú y el de los brotes quitan la transición mientras miden
y la reponen al salir. Si añades una comprobación nueva, no la pongas
detrás de una que abra algo sin ese cuidado.
Lo que el banco no ve, y hay que mirar a ojo:
-
Las fichas de colectivo y los dos calendarios.
-
Los avisos de reserva. El
.gancio-fallbackdeeventos.htmly el<noscript>decalendario.htmlsólo se dibujan cuando el componente externo no carga o no hay JavaScript. Cuando el banco mide, no están, así que sus colores y tamaños no se comprueban solos. Ahí se coló un contraste de 3.4:1. Para revisarlos hay que bloquear el script a mano:nav._envia("Network.enable") nav._envia("Network.setBlockedURLs", {"urls": ["*rosa.frama.io*"]})
Qué NO tocar
El IIFE del calendario semanal (calendario.html, dentro de <script>).
Lleva los horarios escritos a mano en WEEKLY y COLORS, y reglas especiales
—todos los viernes Hacklab salvo el segundo que es Art-Lab; Fridays el segundo
y el último viernes—. Para cambiar un horario se editan esos arrays, no el
resto del código.
Y hay un contrato entre ese script y el CSS: el script escribe
style="--bg:...; --fg:..." en cada píldora de color, y .cal-pill del CSS
las lee con color-mix(). Esas dos variables no se declaran en ninguna parte
del CSS —sólo se usan—, así que parecen sobrar y no sobran. Si se quitan las
reglas que las usan, las píldoras se quedan sin color.
El web component de gancio (eventos.html). Se carga desde
rosa.frama.io y trae la agenda de mad.convoca.la. El identificador del
lugar es places="42", comprobado contra la API.
No se puede recolorear. Durante un tiempo el CSS le pasaba once variables
--calendar-* y aquí ponía que se tematizaba con ellas. Es falso: el
componente las redefine dentro de su propio shadow DOM —una tanda para
.light y otra para .dark— y esa definición gana a la que herede del host.
Comprobado: se le pasaba --calendar-surface:#f5faef y su .calendar seguía
calculando #ffffff. Tampoco expone ningún ::part. Las once variables se
quitaron: no hacían nada.
Lo único que se puede hacer es enmarcarlo desde fuera (borde, radio,
sombra, fondo), que es lo que hay en la regla gancio-calendar, para que la
tarjeta blanca se lea como un panel puesto a propósito.
Cosas pendientes de la asamblea
-
Orden de los colectivos. Los cinco con la ficha sin escribir (
brota) van seguidos al final, así que la segunda fila entera sale desvaída. Repartidos entre las dos filas se leería como "esta hoja está brotando" y no como "la mitad de abajo está apagada". El orden lo decide la asamblea. -
Hacklab: el párrafo de su ficha lo escribí yo de forma provisional porque la sección original no tenía ni una línea de texto. Conviene que lo revise la gente del hacklab y lo ponga en sus palabras.
-
Bicilab: el texto dice «domingos a las 17:00» y el calendario lo pinta a las 19:00. Hay que decidir cuál es la hora buena.
-
«Asamblea ext.» aparece en el calendario semanal pero no tiene color asignado en
COLORS, así que su píldora sale en blanco y no figura en la leyenda. Las otras once etiquetas sí. O se le pone color, o se decide que va neutra a propósito y entonces conviene explicarlo en la leyenda. -
En el calendario la etiqueta pone «Fridays 🌱» y en la leyenda «Fridays for Future». El color sí casa, pero los dos nombres deberían ser el mismo para que la leyenda se entienda.
-
Ficha de Feminismos: pone «el derecho a la libre intervención del embarazo». La expresión habitual es «interrupción», y aquí el cambio de palabra cambia el sentido. No lo he tocado porque el texto es suyo, pero conviene que lo miren.
-
Ficha de Bicilab: «Bocata de espaguetis todos los domingos a las 17:00 nos engrasamos las manos y recuperamos tu bicicleta!» son dos frases pegadas sin puntuación, y a la exclamación le falta el «¡» de apertura. Tampoco lo he tocado: es su voz.
-
Dos botones apuntaban a PDF que no existen (
/archivos/biblioteca.pdfy/archivos/asamblea.pdf). Los quité y dejé el comentario en el HTML: cuando subáis los ficheros, se reponen. -
Las campañas tenían seis botones que no llevaban a ninguna parte. Quitados, con nota en el HTML de lo que prometía cada uno.
La página de error
404.html existe, pero el servidor tiene que saber usarla. Con nginx:
error_page 404 /404.html;
Sin esa línea, un enlace roto enseña el error por defecto del servidor y la página no se usa nunca.
Al compartir el enlace
Todas las páginas llevan og:title, og:description y og:image para que
Mastodon, Telegram o WhatsApp enseñen una vista previa decente. La imagen es
INFO/cso_laenre.jpeg, la foto de la fachada con el cartel pintado a mano.
Una pega conocida: la og:image va en ruta relativa, porque el
dominio propio del sitio no aparece escrito en ningún fichero —todos los
enlaces internos son relativos y las únicas URLs absolutas son de subdominios
(hacklab.laenre.net, okupanel.laenre.net)—. La mayoría de plataformas la
resuelven, pero lo seguro es ponerla absoluta. Cuando confirméis el
dominio, cambiad las ocho líneas og:image por la URL completa.
Accesibilidad
Se ha cuidado y medido:
- Contrastes AA en todos los textos.
- Anillo de foco visible sobre cualquier fondo (en rosa era invisible sobre las propias hojas).
- Nada oculto se puede tabular.
- Áreas de toque medidas en las ocho páginas: todo lo pulsable llega a los
24px que pide WCAG 2.5.8, y casi todo a 44. Lo que queda por debajo son
enlaces dentro de una frase, exentos por la norma.
Ojo con la píldora del calendario en móvil: se ve de 10px pero mide
24, gracias a un relleno vertical con
background-clip:content-box. Necesitabox-sizing:content-box, o elborder-boxglobal se come la altura y la barra desaparece. :activeen todo lo pulsable: en un móvil no hay:hovery sin él el toque no responde..tarjetaqueda fuera a propósito: es undivque no lleva a ninguna parte.color-schemedeclarado:lighten el sitio,darken el Tattoo Circus. Sin eso, un navegador en tema oscuro pinta en oscuro lo que el CSS no controla (barras de desplazamiento, controles, el lienzo inicial).- Las imágenes de contenido llevan texto alternativo que describe la
imagen, no que repite el nombre del colectivo. Si un enlace es sólo una
imagen, el nombre del enlace va en un
aria-labelque dice a dónde va: elaltdescribe el dibujo, y para un enlace eso no sirve. - El logo de la barra lateral va con
alt="", decorativo a propósito: justo debajo hay un<h2>que ya dice «La Enredadera», y conaltpuesto, cuando la imagen no cargaba, el texto se dibujaba recortado dentro de la caja de 48px. - Se respeta
prefers-reduced-motion, y también el retardo: la entrada de la enredadera va escalonada, y anular sólo la duración dejaba las hojas invisibles hasta 0.3s para luego aparecer de golpe.
Límite conocido: al ser CSS puro, las fichas no se cierran con Escape y el contenido de detrás sigue siendo tabulable. Se cierran con la ✕, pulsando fuera o con el botón atrás del navegador. Arreglarlo exigiría JavaScript.