José M. Pérez
Solutions Engineer at Facebook
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Versión A
React
Alicante
2017
Speakers & Schedule
0.0s
0.3s
0.6s
0.9s
1.2s
Versión B
React
Alicante
2017
Speakers & Schedule
0.0s
0.3s
0.6s
0.9s
1.2s
React
Alicante
2017
Speakers & Schedule
React
Alicante
2017
React
Alicante
2017
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
fin = tiempo final en milisegundos
R = % de pantalla renderizado
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
puede, a veces,
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
imágenes
1795kB (54%)
scripts
453kB (14%)
vídeos
756kB (23%)
fuente: http archive 15 agosto 2017
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CONSEJO 1
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
en especial las de mapa de bits (JPG, PNG, WebP...)
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
<img src="example.png"> <!-- el navegador hará la petición -->
@media (max-width: 480px) {
img {
display: none;
}
}
HTML
CSS
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
<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>
.hidden { display: none; }
HTML
CSS
CONSEJO 2
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
gif | png | jpg | webp | <lo_que_venga_después>
<picture>
<source type="image/webp" srcset="2700x1209/mi-imagen.webp 2700w,
1024x1024/mi-imagen.webp 1024w,
600x600/mi-imagen.webp 600w"
sizes="100vw" />
<source srcset="2700x1209/mi-imagen.jpg 2700w,
1024x1024/mi-imagen.jpg 1024w,
600x600/mi-imagen.jpg 600w"
sizes="100vw" />
<img src="600x600/mi-imagen.jpg" alt="Mi preciosa imagen" />
</picture>
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
1 columna
2 columnas
3 columnas
CONSEJO 3
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
<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
IMÁGENES RESPONSIVE
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CONSEJO 4
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
&
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
// 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'));
INTERSECTION OBSERVER
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
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);
}
...
}
INTERSECTION OBSERVER
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
INTERSECTION OBSERVER
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
PLACEHOLDERS
Nada
Placeholder
Color sólido
Carga progresiva o "Blur-up"
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
<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>
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Baseline
Progressive
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.
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
42 x 42px con máxima compresión
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Canny Edge Detector
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
<svg>
<polyline points="51,1 61,1 61,2 56,4 56,3"/>
<polyline points="52,1 50,2 51,3 50,4 50,9 46,10 46,8 48,8 48,9"/>
<polyline points="61,4 61,5 58,6"/>
...
<polyline points="62,58 61,59 61,60 50,62 50,61 51,61"/>
</svg>
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
Que se pueda hacer no significa que se deba hacer
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
CARGANDO IMÁGENES EN LA WEB
@jmperezperez
buscamos desarrolladores web,
preguntadme para saber más
@jmperezperez
By José M. Pérez
Esta charla trata sobre la carga de imágenes en la web. Nos gusta hablar de JS y CSS y cómo optimizarlos, pero tendemos a olvidarnos de las imágenes, que representan más del 50% de los bytes de una página. La petición más eficaz es la que nunca se realiza, y esto supera cualquier optimización de imagen posible. Existen algunos escenarios comunes en los que podemos evitar el uso de imágenes, adoptando un diseño minimalista / flat u ocultando ciertas imágenes en pantallas más pequeñas. Por supuesto, tendremos que usar algunas imágenes en su debido momento. Para estos casos explico cómo el elemento puede ayudar y algunas de sus limitaciones que he encontrado al trabajar con sitios web reales. Uno de ellos es la carga lazy de imágenes, lo que puede aportar grandes ahorros en términos de tráfico de datos, pero también es fácil de implementar erróneamente. Por último, muestro algunas técnicas para "llenar" el espacio de una imagen mientras se carga, pasando de mostrar un área vacía a hacer una carga progresiva desde una imagen borrosa.