【问题标题】:img naturalWidth unexpected return valueimg naturalWidth 意外返回值
【发布时间】:2021-04-27 10:02:16
【问题描述】:

我有这张响应式图片:

<img 
    class="post-card-image" 
    srcset="/content/images/size/w300/2021/04/photo-1459411552884-841db9b3cc2a.jpeg 300w,
           /content/images/size/w600/2021/04/photo-1459411552884-841db9b3cc2a.jpeg 600w,
           /content/images/size/w1000/2021/04/photo-1459411552884-841db9b3cc2a.jpeg 1000w,
           /content/images/size/w2000/2021/04/photo-1459411552884-841db9b3cc2a.jpeg 2000w"
   sizes="(min-width: 1200px) 600px, (min-width: 768px) 50vw, 100vw" 
   src="/content/images/size/w600/2021/04/photo-1459411552884-841db9b3cc2a.jpeg"
   alt="Publishing options"
   loading="lazy" />

在 Firefox 上模拟 iPhone X (375x812 DPR:3) 时,通过检查img.currentSrc 可以看到加载了 2000w 图像。

我的问题是当我检查img.naturalWith 时,这给了我375 的值,它正好是100vw。我期待这会返回图像的原始宽度 20002000/3 = 666

我的问题是为什么img.naturalWith 在这种特殊情况下返回值375

编辑

这是demo of the problem

const img1 = document.getElementById("img-with-srcset");
const img2 = document.getElementById("img-no-srcset");

window.addEventListener('load', (event) => {
  console.log('page is fully loaded');
  
  console.log("img1.naturalWidth : ", img1.naturalWidth);
  console.log("img1.currentSrc : ", img1.currentSrc);
  document.getElementById('meta-1').innerHTML = `Natural Width: ${img1.naturalWidth}<br/>Current src : ${img1.currentSrc}`;

  console.log("img2.naturalWidth : ", img2.naturalWidth);
  console.log("img2.currentSrc : ",img2.currentSrc);
  document.getElementById('meta-2').innerHTML = `Natural Width: ${img2.naturalWidth}<br/>Current src : ${img2.currentSrc}`;  
});
.grid {
  display: grid;
  grid-template-columns: 1fr;
  max-width: 1200px;
  margin: 0 auto;
}

@media (min-width: 768px) {
  .grid {
    grid-template-columns: 1fr 1fr;
  }
}

.card-image {
  position: relative;
  width: 100%;
  height: 300px;
}

.card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<div class="grid">
  <div class="card">
    <div class="card-image">
      <img  id="img-with-srcset"
     srcset="https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=400 400w,
             

https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=600 600w,
                    
https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=800 800w,

https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=2000 2000w" 
sizes="(min-width: 1200px) 600px, (min-width: 768px) 50vw, 100vw" 
src="https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=2000" alt="Writing posts" />  
    </div>  
    <div class="card-meta" id="meta-1"></div>
  </div>
  
  <div class="card">
    <div class="card-image">
      <img  
           id="img-no-srcset"
           src="https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=2000" 
           alt="Writing posts"
       />  
    </div>  
    <div class="card-meta" id="meta-2"></div>
  </div>
</div>

以及在 Firefox 上模拟 iPhone X (375x812 DPR:3) 时的屏幕截图:

第一张图片有srcsetsizes attr,第二张没有。通过检查currentSrc,您可以看到在两种情况下都加载了相同的图像(w=2000),但 naturalWidth 的值不同。两张图片的 CSS 相同。

谢谢

【问题讨论】:

  • 因为that's what it's defined as doing。 MDN 页面包含了相当多的细节,因此可能值得一读(谢天谢地,不是长)。
  • 我在发帖之前确实读到过,上面写着“这是在没有为图像建立约束或特定值时自然绘制图像的宽度。”,这就是我期望这个值的原因到 2000 年
  • 在 MDN 示例中,他们在 css 中使用 200px 的 400x398 图像,naturalWith 返回 400。在我的情况下,我使用以 100vw (375) 渲染的 2000x2450,naturalWith 给我 375 而不是2000
  • 您是否肯定在等待选择加载哪个图像,例如使用 onload 处理程序? MDN 声明他们将代码与负载处理一起运行。仅仅拥有一个 src 可能还不够。
  • 查看设置为 100% 宽度的示例:现在自然宽度是视口的 CSS 像素宽度,已针对 DPI 缩放进行了校正。那么:您的&lt;img&gt; 实际应用了哪些 CSS? IE。 .post-card-image 定义为什么?

标签: javascript html


【解决方案1】:

naturalWidth/Height 返回图像固有的密度校正宽度/高度。

我猜内在维度是什么,对于像 JPEG 这样的位图图像来说非常清楚。
难点是“密度校正”是什么意思。

在内部选择图像源时,它具有current-pixel-density 值。该值确定如下(specs):

  • 如果从图片的src中选择图片源,则为1
  • 如果图像源是从srcset 属性中选择的并且它具有pixel-density-descriptor (nx),则使用此描述符的值。
  • 如果图像源是从srcset 属性中选择的并且它具有width-descriptor,则像素密度表示宽度描述符值除以使用的源大小。此源大小是在&lt;source&gt;sizes 属性中定义的。

这是第三种情况。
为了让它不那么动态,让我们在sizes 属性中设置一个唯一的50vw 值。

const img1 = document.getElementById("img-with-srcset");

window.addEventListener('load', (event) => {
  console.log("img1.naturalWidth : ", img1.naturalWidth);
  console.log("img1.currentSrc : ", img1.currentSrc);
  const src = img1.currentSrc;
  const width_descriptor = src.slice(src.lastIndexOf("w=") + 2);
  // in our case the intrinsic width is the same as width_descriptor
  const intrinsic_width = width_descriptor;
  const source_size = innerWidth * 0.5; // 50vw
  const density = width_descriptor / source_size;
  const expected_size = intrinsic_width / density;
  console.log( "expected : ", expected_size );
});
<img  id="img-with-srcset"
  srcset="https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=400 400w,
    https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=600 600w,
    https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=800 800w,
    https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=2000 2000w" 
  sizes="50vw" 
  src="https://images.unsplash.com/photo-1509587584298-0f3b3a3a1797?w=2000" alt="Writing posts" />

因此,在这种没有像素密度描述符的情况下,naturalWidth/Height 值确实取决于所选的size 值,该值本身可以相对于视口的大小。

不知道你愿意做什么很难走得更远,但请注意there is a proposal 公开&lt;source&gt; 的当前大小。

【讨论】:

  • 谢谢。所以我想我们不应该使用naturalWidth 来获取文件中的“真实”img 宽度?
  • 是的,他们在我的脑海中打破了它......不过,您仍然可以使用非屏幕图像,使用 currentSrc
猜你喜欢
  • 2010-12-11
  • 2020-12-08
  • 2020-06-24
  • 1970-01-01
  • 1970-01-01
  • 2013-06-26
  • 2014-12-11
  • 2016-01-30
  • 1970-01-01
相关资源
最近更新 更多