响应图像:来自JavaScript的set sizes属性

时间:2018-05-02 10:41:37

标签: javascript responsive-design responsive-images srcset

可以从JavaScript设置srcset属性以实现响应性延迟加载图像。

但是,设置sizes属性似乎不起作用。 HTML中的编码sizes按预期工作,但是当我尝试从JavaScript设置sizes属性时(如下面的代码中所示),它没有任何效果:所选图像与视口宽度匹配并且不会#39 ; t遵循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 个答案:

答案 0 :(得分:1)

我运行了你的样本,它正常工作,正如我预期的那样。

大小编码的方式可能有问题。
我认为放置 min-width:0px 媒体条件并不是一个好主意,因为它将始终被选中,所有其他条件将被忽略。

从这里https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images

  

浏览器在第一个匹配条件后忽略所有内容,因此请注意如何订购媒体条件。

答案 1 :(得分:0)

根据@ 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';
  }
}