ResizeObserver: una nueva herramienta poderosa para trabajar con adaptabilidad

¡Buen dia amigos!

La capacidad de respuesta es uno de los estándares del desarrollo web. Hay una gran cantidad de resoluciones de pantalla, y este número aumenta todo el tiempo. Nos esforzamos por admitir todos los tamaños de pantalla posibles mientras mantenemos una interfaz de usuario amigable. Una excelente solución a este problema son las consultas de medios (consultas de medios). ¿Pero qué pasa con los componentes web? El desarrollo web moderno se basa en componentes, y necesitamos una forma de hacerlos receptivos. Hoy quiero hablar sobre la API ResizeObserver, que le permite monitorear (observar) los cambios en el tamaño de un elemento en particular, y no toda la ventana gráfica, como es el caso de las consultas de medios.

Un poco de historia


Anteriormente, solo teníamos consultas de medios a nuestra disposición: una solución CSS basada en el tamaño, tipo y resolución de la pantalla de un dispositivo de medios (por un dispositivo de medios, me refiero a una computadora, teléfono o tableta). Las consultas de medios son bastante flexibles y fáciles de usar. Durante mucho tiempo, las consultas de medios solo estaban disponibles en CSS, ahora también están disponibles en JS a través de window.matchMedia (mediaQueryString). Ahora podemos verificar desde qué dispositivo se visualiza la página y también controlar el cambio en el tamaño del área de visualización (estamos hablando del método MediaQueryList.addListener () - aprox.

Consultas de elementos


Lo que nos faltaba era la capacidad de monitorear el tamaño de un solo elemento DOM, y no solo toda la ventana gráfica. Los desarrolladores se han quejado de esto durante muchos años. Esta es una de las características más esperadas. En 2015, incluso se presentó una propuesta: solicitudes de tamaños de contenedores ( consultas de contenedores ):
Los desarrolladores a menudo necesitan la capacidad de diseñar elementos cuando cambian el tamaño de su contenedor principal, independientemente del área de visualización. Las solicitudes de tamaños de contenedores les dan esta oportunidad. Ejemplo de uso de CSS:
pantalla .element: media (min-width: 30em) {***}
Suena genial, pero los vendedores de navegadores tenían una buena razón para rechazar esta propuesta: dependencia circular (dependencia circular) (cuando un tamaño define a otro, esto conduce a un bucle infinito (se puede encontrar más sobre esto aquí ). ¿Qué otras opciones hay? Podemos usar window.resize (devolución de llamada), pero esto es un "placer costoso": se llamará una devolución de llamada cada vez que ocurra un evento, y necesitaremos muchos cálculos para determinar que el tamaño de nuestro componente realmente ha cambiado ...

Cambiar el tamaño del elemento utilizando la API ResizeObserver


Conozca la API ResizeObserver de Chrome:
La API ResizeObserver es una interfaz para el seguimiento del cambio de tamaño del elemento. Este es un tipo de análogo del evento window.resize para un elemento.

La API ResizeObserver es un borrador en vivo. Ya está implementado en Chrome, Firefox y Safari para PC. El soporte móvil es menos impresionante: solo Chrome en Android y Samsung Internet. Desafortunadamente, no existe un polifilo completo. Los polífilos disponibles contienen algunas limitaciones (por ejemplo, una respuesta lenta al cambio de tamaño o la falta de soporte para una transición sin problemas). Sin embargo, esto no debería impedirnos probar esta API. ¡Hagamoslo!

Ejemplo: cambiar texto al cambiar el tamaño de un elemento


Imagine la siguiente situación: el texto dentro del elemento debería cambiar según el tamaño del elemento. La API ResizeObserver proporciona dos herramientas: ResizeObserver y ResizeObserverEntry. ResizeObserver se usa para rastrear el tamaño de un elemento, y ResizeObserverEntry contiene información sobre el elemento que ha cambiado de tamaño.
El código es muy simple:

<h1> size </h1>
<h2> boring text </h2>

const ro = new ResizeObserver(entries => {
    for(let entry of entries){
        const width = entry.contentBoxSize
        ? entry.contentBoxSize.inlineSize
        : entry.contentRect.width

        if(entry.target.tagName === 'H1'){
            entry.target.textContent = width < 1000 'small' : 'big'
        }

        if(entry.target.tagName === 'H2' && width < 500){
            entry.target.textContent = `I won't change anymore`
            ro.unobserve(entry.target) //  ,     500px
        }
    }
})

//       
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))

Primero, cree un objeto ResizeObserver y pásele una función de devolución de llamada como parámetro:

const resizeObserver = new ResizeObserver((entries, observer) => {
    for(let entry of entries){
        // 
    }
})

Se llama a la función cada vez que se cambia el tamaño de uno de los elementos contenidos en ResizeObserverEntries. El segundo parámetro de la función de devolución de llamada es el propio observador. Podemos usarlo, por ejemplo, para detener el seguimiento cuando se cumple una determinada condición.

La devolución de llamada obtiene una matriz de ResizeObserverEntry. Cada entrada contiene las dimensiones del elemento observado (objetivo).

for(let entry of entries){
    const width = entry.contentBoxSize
    ? entry.contentBoxSize.inlineSize
    : entry.contentRect.width

    if(entry.target.tagName === 'H1'){
        entry.target.textContent = width < 1000 ? 'small' : 'big'
    }
    ...
}

Tenemos tres propiedades que describen el tamaño de un elemento: borderBoxSize, contentBoxSize y contentRect. Representan el modelo de caja del elemento, del que hablaremos más adelante. Ahora unas pocas palabras sobre el apoyo. La mayoría de los navegadores admiten contentRect, sin embargo, aparentemente, esta propiedad quedará en desuso:
contentRect apareció en la etapa de desarrollo preliminar de ResizeObserver y se agregó solo en aras de la compatibilidad actual. Probablemente en el futuro se considerará obsoleto.


Por lo tanto, recomendaría usar contentRect junto con bordeBoxSize y contentBoxSize. ResizeObserverSize incluye dos propiedades: inlineSize y blockSize, que pueden interpretarse como ancho y alto (siempre que trabajemos en la orientación horizontal del texto - modo de escritura: horizontal).

Observación de elementos


Lo último que debe hacer es comenzar a rastrear el artículo. Para hacer esto, llamamos a ResizeObserver.observe (). Este método agrega un nuevo objetivo a la lista de elementos observados. Podemos agregar a esta lista uno o varios elementos a la vez:

// resizeObserver(target, options)
ro.observe(document.querySelector('h1'))
ro.observe(document.querySelector('h2'))

El segundo parámetro es "opcional". Hasta la fecha, la única opción disponible es box, que define un modelo de bloque. Los valores posibles son content-box (predeterminado), border-box y device-pixel-content-box (solo Chrome). Solo se puede definir un modelo de bloque en un ResizeObserver.

Para detener la supervisión, use ResizeObserver.unobserve (target). Para dejar de seguir todos los elementos, use ResizeObserver.disconnect ().

Modelo de bloque


El cuadro de contenido es el contenido del bloque sin relleno, borde y margen. El cuadro de borde incluye relleno y borde (sin margen).



El cuadro de contenido de píxeles del dispositivo es el contenido del elemento en píxeles físicos. No he visto ejemplos del uso de este modelo, pero parece que esto puede ser útil al trabajar con el lienzo. Aquí hay una discusión interesante sobre este tema en Github.

¿Cuándo se entera un observador de los cambios?


Se llama a una devolución de llamada cada vez que se cambia el tamaño del elemento de destino. Esto es lo que dice la especificación al respecto:

  • La observación se activa cuando un elemento observado se agrega / elimina del DOM.
  • La observación se activa cuando la propiedad de visualización del elemento observado se establece en none.
  • La observación no funciona para elementos de línea "no sustituidos".
  • La observación no funciona en la transformación CSS.
  • , , .. , 0,0.

Según el primer párrafo, podemos determinar el cambio en el contenedor principal al cambiar sus elementos secundarios. Un gran ejemplo de tal uso de la API ResizeObserver es desplazarse hacia abajo en la ventana de chat al agregar un nuevo mensaje. Un ejemplo se puede ver aquí .

¿Recuerdas las consultas de tamaño de contenedor que mencioné anteriormente? ¿Sobre su problema de dependencia circular? Por lo tanto, la API ResizeObserver tiene una solución integrada para evitar un bucle sin fin de "cambio de tamaño". Lee sobre esto aquí .

Gracias por su atención.

Enlaces útiles: MDN CanIUse

Specification Primer artículo del equipo de desarrollo Polyfil más popular



Source: https://habr.com/ru/post/undefined/


All Articles