Адаптивные изображения: установите атрибут размеров из JavaScript
srcset
атрибут может быть установлен из JavaScript для реализации адаптивных ленивых загруженных изображений.
Тем не менее, установка sizes
Атрибут не работает. кодирование sizes
в HTML работает как положено, но когда я пытаюсь установить sizes
атрибут из JavaScript (как в коде ниже) не имеет никакого эффекта: выбранное изображение соответствует ширине области просмотра и не следует за sizes
намеки.
Это по замыслу или просто не реализовано?
Пример кода ниже.
const BASE_URL = 'https://res.cloudinary.com/foobar/f_auto,dpr_auto,q_auto:eco/';
const SIZES = {
0: 'calc(100vw - 60px)',
420: 'calc((100vw - 90px) / 2)',
750: 'calc((100vw - 120px) / 3)',
1200: 'calc((100vw - 150px) / 4)'
}
const WIDTHS = [500, 1000, 1500];
const options = {
rootMargin: '0px 0px 100px 0px',
};
function callback(entries) {
for (const entry of entries) {
if (entry.isIntersecting) {
const lazyImage = entry.target;
const id = lazyImage.dataset.id;
lazyImage.sizes = getSizes();
lazyImage.srcset = getSrcset(id);
io.unobserve(lazyImage);
}
}
}
function getSrcset(id) {
const srcset = [];
for (const width of WIDTHS) {
srcset.push(`${BASE_URL}w_${width}/${id}.jpg ${width}w`);
}
return srcset.join(',');
}
function getSizes() {
const sizes = [];
for (const size in SIZES) {
sizes.push(`(min-width: ${size}px) ${SIZES[size]}`);
}
return sizes.join(',');
}
const images = document.querySelectorAll('img.lazy');
let io;
if (window.IntersectionObserver) {
io = new IntersectionObserver(callback, options);
}
for (const image of images) {
if (window.IntersectionObserver) {
io.observe(image);
} else {
console.log('Intersection Observer not supported');
image.src = BASE_URL + image.getAttribute('data-id' + '.jpg');
}
}
2 ответа
Я проверил ваш образец, и он работает нормально, как и ожидалось для меня.
Возможно, что-то не так с тем, как кодируются размеры.
Я думаю, что не очень хорошая идея ставить медиа-условие min-width: 0px, так как оно всегда будет выбрано, а все остальные условия будут игнорироваться.
Отсюда https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images
Браузер игнорирует все после первого соответствия условий, поэтому будьте осторожны при заказе условий мультимедиа.
Согласно комментарию @amed0zmey, я исправил это, получив sizes
Код правильный.
Рабочий пример ниже.
const BASE_URL = 'https://res.cloudinary.com/foo/f_auto,dpr_auto,q_auto:eco/';
const BREAKPOINTS = [0, 420, 750, 1200];
const DISPLAY_WIDTHS = ['calc(100vw - 60px)', 'calc((100vw - 90px) / 2)',
'calc((100vw - 120px) / 3)', 'calc((100vw - 150px) / 4)'];
const IMAGE_WIDTHS = [500, 1000, 1500];
const options = {
rootMargin: '0px 0px 100px 0px',
};
function callback(entries) {
for (const entry of entries) {
if (entry.isIntersecting) {
const image = entry.target;
const id = image.dataset.id;
image.srcset = getSrcset(id);
io.unobserve(image);
}
}
}
function getSrcset(id) {
const srcset = [];
for (const width of IMAGE_WIDTHS) {
srcset.push(`${BASE_URL}w_${width}/${id}.jpg ${width}w`);
}
return srcset.join(',');
}
function getSizes() {
const sizes = [];
for (let i = 0; i !== BREAKPOINTS.length; ++i) {
let size = `(min-width: ${BREAKPOINTS[i]}px) `;
const nextBreakpoint = BREAKPOINTS[i + 1];
if (nextBreakpoint) {
size += `and (max-width: ${nextBreakpoint}px) `;
}
size += DISPLAY_WIDTHS[i];
sizes.push(size);
}
return sizes.join(',');
}
const images = document.querySelectorAll('img.lazy');
let io;
if (window.IntersectionObserver) {
io = new IntersectionObserver(callback, options);
}
for (const image of images) {
image.sizes = getSizes();
if (window.IntersectionObserver) {
io.observe(image);
} else {
console.log('Intersection Observer not supported');
const id = image.getAttribute('data-id');
image.srcset = getSrcset(id);
image.src = BASE_URL + 'id' + '.jpg';
}
}