为什么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
相关产品推荐
相关产品推荐

