You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Safari中获取背景图片宽度为0,Chrome和火狐中为225px?

问题根因
  • 核心原因是你在动态创建Image对象并赋值src后,未等待图片加载完成就同步读取宽高属性:Chrome和Firefox对已缓存的资源会直接同步返回宽高,但Safari的加载策略更保守,即使资源已在缓存中,刚赋值src的Image对象也需要等待load事件触发后才能获取到正确的宽高,此时同步读取只能拿到0。
  • 次要问题:你的.img元素没有显式设置宽高,getComputedStyle读取到的元素本身宽高可能为0,也会影响后续背景图尺寸的计算结果。
修复方案

1. 将获取逻辑改为异步(必改)

用Promise封装加载逻辑,等待图片加载完成后再计算尺寸,修改后的getBackgroundSize参考代码如下:

function getBackgroundSize(elem) {
  return new Promise((resolve) => {
    const computedStyle = getComputedStyle(elem),
      image = new Image(),
      src = computedStyle.backgroundImage.replace(/url\((['"])?(.*?)\1\)/gi, "$2"),
      cssSize = computedStyle.backgroundSize,
      elemW = parseInt(computedStyle.width.replace("px", ""), 10),
      elemH = parseInt(computedStyle.height.replace("px", ""), 10),
      elemDim = [elemW, elemH],
      computedDim = [];
    let ratio;
    image.src = src;
    // 加载完成后再处理计算逻辑
    const calculate = () => {
      ratio = image.width > image.height ? image.width / image.height : image.height / image.width;
      cssSize = cssSize.split(" ");
      computedDim[0] = cssSize[0];
      computedDim[1] = cssSize.length > 1 ? cssSize[1] : "auto";
      if (cssSize[0] === "cover") {
        if (elemDim[0] > elemDim[1]) {
          if (elemDim[0] / elemDim[1] >= ratio) {
            computedDim[0] = elemDim[0];
            computedDim[1] = "auto";
          } else {
            computedDim[0] = "auto";
            computedDim[1] = elemDim[1];
          }
        } else {
          computedDim[0] = "auto";
          computedDim[1] = elemDim[1];
        }
      } else if (cssSize[0] === "contain") {
        if (elemDim[0] < elemDim[1]) {
          computedDim[0] = elemDim[0];
          computedDim[1] = "auto";
        } else {
          if (elemDim[0] / elemDim[1] >= ratio) {
            computedDim[0] = "auto";
            computedDim[1] = elemDim[1];
          } else {
            computedDim[1] = "auto";
            computedDim[0] = elemDim[0];
          }
        }
      } else {
        for (let i = cssSize.length; i--; ) {
          if (cssSize[i].indexOf("px") > -1) {
            computedDim[i] = cssSize[i].replace("px", "");
          } else if (cssSize[i].indexOf("%") > -1) {
            computedDim[i] = elemDim[i] * (cssSize[i].replace("%", "") / 100);
          }
        }
      }
      if (computedDim[0] === "auto" && computedDim[1] === "auto") {
        computedDim[0] = image.width;
        computedDim[1] = image.height;
      } else {
        ratio = computedDim[0] === "auto" ? image.height / computedDim[1] : image.width / computedDim[0];
        computedDim[0] = computedDim[0] === "auto" ? image.width / ratio : computedDim[0];
        computedDim[1] = computedDim[1] === "auto" ? image.height / ratio : computedDim[1];
      }
      resolve({
        width: computedDim[0],
        height: computedDim[1]
      });
    }
    // 已经加载完成直接计算,否则等load事件
    if (image.complete && image.naturalWidth > 0) {
      calculate();
    } else {
      image.onload = calculate;
      // 可选:加onerror处理异常场景
      image.onerror = () => resolve({width: 0, height: 0});
    }
  })
}

// 调用方式改为异步
async function abc() {
  const size = await getBackgroundSize(document.querySelector(".img"));
  console.log(size);
}

2. 补充元素宽高(必改)

给.img元素设置明确的宽高,例如:

.img {
  background: url("./download.jpeg") no-repeat left;
  width: 300px;
  height: 200px;
}

3. 可选优化

如果需要兼容更老的Safari版本,可以给Image对象设置crossOrigin属性,避免跨域图片的宽高读取被拦截。

内容的提问来源于stack exchange,提问作者user944513

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 07:42:01