Cargando imágenes de una forma óptima José M. Pérez · Desarrollador Web en Spotify @jmperezperez
http://spoti.fi/alicante-frontend
Slide 2
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Qué hago
Slide 3
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 4
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Page Load Time
Slide 5
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
0.0s
0.3s
0.6s
0.9s
1.2s React Alicante
Versión A
2017
Speakers & Schedule
0.0s
Versión B
0.3s
0.6s
0.9s
1.2s
React Alicante
React Alicante
React Alicante
React Alicante
2017
2017
2017
2017
Speakers & Schedule
Speakers & Schedule
Slide 6
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Rendimiento percibido por el usuario (User Perceived Performance)
Slide 7
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
SpeedIndex =
f in ∫0
1−
fin = tiempo final en milisegundos R = % de pantalla renderizado
R 100
Slide 8
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
WebPageTest
Slide 9
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 10
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Más kilobytes puede, a veces,
mejorar el rendimiento percibido
Slide 11
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Evitando esto:
Slide 12
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Técnicas para mejorar el rendimiento percibido Server-side rendering Critical CSS JS Async Fuentes Async
Slide 13
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
¿Qué pasa con las imágenes?
Slide 14
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
imágenes
vídeos
scripts
1795kB (54%)
756kB (23%)
453kB (14%) fuente: http archive 15 agosto 2017
Slide 15
Slide 16
Usar o no usar imágenes
Slide 17
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CO N
SE
JO
1
Reduce las peticiones de imágenes en especial las de mapa de bits (JPG, PNG, WebP...)
Slide 18
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Minimalismo | Diseño Flat
Slide 19
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Hace no mucho tiempo...
Slide 20
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 21
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 22
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Cómo NO ocultar imágenes (1/2) CSS @media (max-width: 480px) { img { display: none; } }
HTML <img src="example.png"> <!-- el navegador hará la petición -->
Slide 23
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Cómo NO ocultar imágenes (2/2) CSS .hidden { display: none; }
HTML <body> <section class="section-1"> <p>Esta es la sección actual</p> <img src="example-1.png"> </section> <section class="section-2 hidden"> <p>Esta sección quizás se muestre luego</p> <img src="example-2.png"> <!-- el navegador pedirá esta imagen --> </section> </body>
Slide 24
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CO N
SE
JO
2
Optimiza tus imágenes
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
compresión · sin pérdida (lossless) · perceptual
Slide 28
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Responsive
1 columna
2 columnas
CO N
SE
3 columnas
JO
3
Slide 29
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
IMÁGENES RESPONSIVE
Ejemplo <img sizes="(max-width: 30em) 100vw, (max-width: 50em) 50vw, calc(33vw - 100px)" srcset="profile-200.jpg 200w, profile-400.jpg 400w, profile-800.jpg 800w, profile-1600.jpg 1600w" src="profile-400.jpg" alt="Alicante">
Reto: Mantener sincronizado el markup y el CSS
Slide 30
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CO N
SE
JO
Usar lazy-loading en imágenes
4
Slide 31
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
<img> encima del fold &
Lazy debajo del fold
Slide 32
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Intersection Observer
Slide 33
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
INTERSECTION OBSERVER
Ejemplo // cargar imagen cuando esté a <= 100 px del viewport const options = { rootMargin: '100px' } const callback = entries => { entries.forEach(entry => { if (entry.intersectionRatio > 0) { // cargar imagen } }); }; const observer = new IntersectionObserver(callback, options); observer.observe(document.querySelector('.lazy-img'));
Slide 34
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
INTERSECTION OBSERVER
Encapsulación en React class LazyImage extends React.Component { constructor() { this.observer = new IntersectionObserver(entries => { if (entries[0].intersectionRatio > 0) { // ¡hacer la petición! } }); this.element = null; /* render() le dará valor a través de un ref */ } componentDidMount() { this.observer.observe(this.element); } componentWillUnmount() { this.observer.unobserve(this.element); } ... }
Slide 35
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
INTERSECTION OBSERVER
Soporte
Slide 36
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Qué mostrar mientras la imagen se está cargando
Slide 37
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
PLACEHOLDERS
Opciones
Nada
Placeholder
Color sólido
Carga progresiva o "Blur-up"
Slide 38
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Ejemplos de colores sólidos
Slide 39
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 40
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 41
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 42
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 43
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Slide 44
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Ejemplos de carga progresiva de imágenes
Slide 45
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Medium
Slide 46
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Medium
Slide 47
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Quartz (qz.com)
Slide 48
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Quartz (qz.com)
Slide 49
CARGANDO IMÁGENES EN LA WEB
Quora
@jmperezperez
Slide 50
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Cómo se hace
Slide 51
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
HTML - Medium <figure> <div> <div/> <!-- este div mantiene el espacio con la correcta proporción de la imagen, para que no se "colapse" --> <img/> <!-- pequeña imagen con baja resolución (por ejemplo 27x17) y baja calidad --> <canvas/> <!-- toma la imagen anterior y aplica filtro "blur" --> <img/> <!-- la imagen final (grande) que se va a mostrar --> <noscript/> <!-- fallback para cuando no hay JS --> </div> </figure>
Slide 52
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
JPEGs progresivos
Baseline
Progressive
Fuente: https://blog.codinghorror.com/progressive-image-rendering/
Slide 53
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Con el método de JPEGs progresivos [...] la fluidez “ cognitiva se inhibe y el cerebro tiene que hacer un
mayor esfuerzo para darle sentido a lo que se está mostrando. — De Progressive image rendering: Good or evil?
Slide 54
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Thumbnails
42 x 42px con máxima compresión Fuente: https://jmperezperez.com/webp-placeholder-images/
Slide 55
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Siendo creativos con SVGs
Slide 56
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
SVG
Fuente: https://www.polygon.com/a/ps4-review
Slide 57
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
SVG
Fuente: https://www.polygon.com/a/xbox-one-review
Slide 58
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Dibujando con SVG
">//codepen.io/jmperez/embed/rxxRRg/?height=525&themeid=0&default-tab=js,result&embed-version=2">
Fuente: https://codepen.io/jmperez/pen/rxxRRg
Slide 59
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Dibujando imágenes de mapa de bits
Canny Edge Detector
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
https://jmperezperez.com/contour/
Fuente: https://jmperezperez.com/contour/
Slide 62
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Cómo dibujar imágenes 1. Buscar el contorno con un detector de bordes Canny 2. Crear líneas 3. Usar JS y SVG para animar <svg> <polyline <polyline <polyline ... <polyline </svg>
points="51,1 61,1 61,2 56,4 56,3"/> points="52,1 50,2 51,3 50,4 50,9 46,10 46,8 48,8 48,9"/> points="61,4 61,5 58,6"/> points="62,58 61,59 61,60 50,62 50,61 51,61"/>
Slide 63
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
¿Deberíamos hacer esto? Que se pueda hacer no significa que se deba hacer
Slide 64
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Resumen Reducir peticiones Elegir el formato adecuado y optimizar Utilizar imágenes responsive Aplicar lazy loading ¡Innovar!
Slide 65
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Desarrollar Web es divertido.. divertido
Slide 66
spotify.com/jobs buscamos desarrolladores web, preguntadme para saber más