ns-frame0.18

Mosaico (ns-frame/mosaic)

Un bento donde las piezas no tienen que ser rectángulos. Cada área se dibuja con celdas, como en grid-template-areas, pero puede tener forma de L, T, U o escalera. Las piezas encajan entre sí con el mismo hueco en las rectas y en las curvas, y uno o varios orbes pueden abrir un hueco que recorta a sus vecinas.

<script type="module" src="ns-frame.js"></script>
<script type="module" src="ns-mosaic.js"></script>

<div class="ns-mosaic hero-grid" data-ns-mosaic="wave ripple">
  <article data-ns-area="h">Portada</article>
  <article data-ns-area="a">…</article>
  <article data-ns-area="b">…</article>
  <article data-ns-area="x">…</article>
  <article data-ns-area="y">…</article>
  <div data-ns-orb><img src="foto.jpg" alt="…"></div>
</div>
.hero-grid {
  --ns-areas: 'a h h b' 'a h h b' 'x x y y';
  --ns-row: 150px;
  --ns-gap: 14px;
  --ns-mosaic-radius: 22px;
  --ns-orb: 3 3 90 hex;
}
@media (max-width: 760px) {
  .hero-grid { --ns-areas: 'h h' 'h h' 'a b' 'x y'; --ns-orb: 2 3 56 hex; --ns-row: 120px }
}

Plantilla

Variable Qué hace Por defecto
--ns-areas Filas entre comillas; cada nombre es un área; . deja la celda vacía —
--ns-row Alto de cada fila 150px
--ns-gap Hueco entre piezas 14px
--ns-mosaic-radius Radio de las esquinas convexas 18px
--ns-mosaic-radius-in Radio de las esquinas cóncavas el radio + hueco
--ns-mosaic-radius-out Radio de las esquinas del contorno exterior del mosaico el radio

Hasta ahora se llamaban --ns-round, --ns-round-in y --ns-round-out, --ns-orb-round y --ns-mo-*: siguen funcionando. Los nombres nuevos siguen la convención de toda la librería (--ns-<módulo>-radius, --ns-<módulo>-…-time). | --ns-pad | Padding del contenido de cada pieza | 22px |

  • Hueco constante: las esquinas cóncavas miden el radio más el hueco, así que una esquina convexa que encaja en una cóncava deja la misma distancia en la curva.
  • Responsive con CSS: la plantilla es una variable. Cámbiala con media queries o container queries; al cambiar, las piezas se reubican (y con View Transitions se animan).
  • El texto recorre toda la figura: en una pieza que no es un rectángulo (L, T, escalera o mordida por un orbe), el texto fluye línea a línea por todo el contorno real, curvas incluidas, con --ns-pad de margen en cada punto del borde. Se hace con shape-outside nativo: el motor mide la silueta y coloca unos flotantes invisibles (.ns-fl y .ns-fr, con aria-hidden) al principio de la pieza. En este modo la pieza lleva la clase .ns-flow y display: flow-root, así que su contenido debe ser de bloque o en línea: un hijo con display: flex, grid u overflow: hidden se coloca como un rectángulo entero debajo de los flotantes. Para piezas que maquetas tú (por ejemplo, alineadas abajo con flex), usa data-ns-flow="off" en el mosaico o en la pieza.
  • Rectángulos: en las piezas rectangulares, y con data-ns-flow="off", el contenido va en un rectángulo de celdas. Si el mayor no basta, el motor prueba los demás (en una L, el brazo largo y el ancho) y elige el primero donde el contenido cabe entero. Al cargar las fuentes web se vuelve a medir.
  • Accesible: el orden del DOM no cambia; sólo cambia dónde se dibuja cada pieza.
  • Cada hijo necesita data-ns-area. Un área que no aparece en la plantilla se oculta.

Orbes

--ns-orb: 3 3 96;                      /* columna, fila, radio: un círculo */
--ns-orb: 3 3 86 hex;                  /* hexágono (el radio es la apotema) */
--ns-orb: 3 3 70 diamond 15;           /* rombo girado 15° */
--ns-orb: 3 3 70 hex, 2 4 44 circle;   /* varios, cada uno con su forma */
  • La posición va en líneas de la cuadrícula: 1 es el borde inicial y 3 es el hueco entre la columna 2 y la 3. Se admiten decimales.
  • Formas: circle, hex, diamond, square, tri y oct.
  • El hueco es concéntrico con el orbe: los lados se desplazan el valor de --ns-orb-gap (por defecto, el hueco del mosaico) y las esquinas repiten el radio de --ns-orb-corner más ese hueco. Donde el borde de la pieza se une al hueco hay una curva de enlace de radio --ns-orb-radius.
  • Cada orbe de la lista se empareja, en orden, con un hijo [data-ns-orb], que se posiciona y recorta solo. Puede tener contenido: una foto, un dato o un botón. Si sólo es decoración, pon aria-hidden="true".

Luz conectada (data-ns-mosaic)

Efectos que tratan todo el mosaico como una sola figura. Se combinan libremente:

Valor Dónde Qué hace
wave bordes y fondos Ondas que salen del primer orbe (o del centro) y cruzan todas las piezas
ripple bordes y fondos Una onda nace donde tocas o haces clic
glow bordes y fondos Una luz sigue al puntero por toda la figura
sweep bordes y fondos Un barrido diagonal recorre el mosaico
scan bordes y fondos Una línea horizontal baja por el mosaico
stream bordes Corriente: tres luces corren por los bordes de las propias piezas y, donde una pieza toca a su vecina, cruzan el hueco y siguen por el borde de la siguiente (también por el anillo de los orbes), en rutas distintas. Cada luz se desvanece en degradado y lleva un foco que enciende los bordes por donde pasa. --ns-mosaic-speed (px/s, 160)
trace bordes Una luz corta recorre a la vez el contorno de cada pieza
pulse bordes Todos los bordes respiran juntos
aurora fondos Dos manchas de color derivan despacio por toda la figura
dots / grid fondos Puntos o retícula continuos: el patrón no se corta entre piezas

Ajustes: --ns-mosaic-light (color de la luz), --ns-mosaic-width (grosor en los bordes), --ns-mosaic-fx-time (duración), --ns-mosaic-fill (intensidad sobre los fondos), --ns-mosaic-a1 y --ns-mosaic-a2 (colores de la aurora), --ns-mosaic-dot y --ns-mosaic-line (color de los patrones). (--ns-mosaic-time es otra cosa: la duración de arrange().) Además, --ns-mosaic-glow-size (radio de la luz que sigue al puntero, 240) y --ns-mosaic-ripple-time (duración de la onda al tocar: 1100, 1100ms o 1.1s). Las duraciones y el color cambian al momento; la velocidad de stream y los dos últimos, con refresh().

Los efectos se combinan (data-ns-mosaic="stream dots"), pero cada uno suma trabajo: en una página para móviles, uno o dos. Fuera de la pantalla se pausan solos.

Móvil y escritorio por separado. En pantallas táctiles (hover: none y pointer: coarse) no hay un puntero que flote: glow no tiene a quién seguir y ripple convierte cada toque, que casi siempre es para hacer scroll, en una onda. Por eso en táctil se quitan esos dos por defecto. Para elegir tú qué efectos se ven en táctil, usa data-ns-mosaic-touch (vacío = ninguno):

<div class="ns-mosaic" data-ns-mosaic="glow ripple trace" data-ns-mosaic-touch="trace">

Si el dispositivo cambia de modo (una tableta a la que se conecta un ratón), la lista se vuelve a elegir sola.

  • Los bordes y las luces usan una sola capa sobre el mosaico, con los contornos de todas las piezas como máscara (una imagen que se rasteriza al cambiar la figura). La aurora y los patrones van en un ::before de cada pieza, por detrás del contenido, alineados en coordenadas del mosaico.
  • Las luces se mueven en el compositor: cada una es una capa que sólo cambia con transform u opacity, y el resplandor de los bordes son dos filtros CSS (un halo desenfocado y un drop-shadow), no un filtro SVG (bajo el que nada va a la GPU). El trazo libre (trace) es el único que se repinta: un trazo discontinuo que avanza no tiene equivalente ahí. Las animaciones se pausan fuera de pantalla (y siguen donde iban al volver), se desactivan con prefers-reduced-motion, y en alto contraste la capa desaparece.
  • Las capas animadas sólo se rehacen si cambian la figura o los efectos: un resize que no cambia nada (en el móvil, la barra del navegador al subir y bajar) no reinicia las animaciones.
  • Como ::before queda para los fondos compartidos, no combines aurora, dots o grid con las clases de patrón de ns-fx.css en la misma pieza.

API

import { refresh, parseAreas } from 'ns-frame/mosaic'
refresh()                                 // recalcula (p. ej. tras cambiar --ns-orb desde JS)
parseAreas("'a a b' 'c d b'")             // [['a','a','b'], ['c','d','b']]

Buenas prácticas: entre 5 y 10 piezas, una pieza ancla clara, orbes en cruces de líneas (donde se tocan 3 o 4 piezas) y filas lo bastante altas para que el recorte del orbe no se coma el texto.