CSS格式化SVG实现横向滚动成就横幅的跨浏览器兼容问题
解决方案
你不需要更换整个横向滚动横幅的实现思路,SVG格式的标识完全可以在这类效果里正常运行,现在的异常基本是几个配置和逻辑问题导致的,对应修复即可:
问题根源
- 混合内容拦截:你代码里引用的所有SVG资源都是HTTP协议,当前主流浏览器默认会阻止HTTPS站点加载HTTP类型的图片资源,直接导致图片加载失败。
- 尺寸计算时序错误:现有JS逻辑在DOM结构加载完成后就立刻执行元素宽度计算、节点克隆操作,但此时SVG图片还未完成加载,通过
getBoundingClientRect()获取到的图片宽度为0,后续滚动距离计算、无缝克隆的逻辑全部失效。 - 资源配置错误:如果你的服务器给SVG文件返回的
Content-Type响应头不是image/svg+xml,浏览器不会将资源识别为可渲染的图片;另外如果导出的SVG文件缺失viewBox、基础宽高属性,也会出现渲染异常。 - 布局挤压问题:滚动容器的包裹层用了flex布局,但是图片元素没有设置禁止收缩,会被flex布局自动压缩宽度,导致展示错乱。
- 闭包变量问题:原JS的循环中用
var声明变量,setTimeout回调执行时会拿到错误的变量引用,多横幅场景下滚动逻辑会完全错乱。
修复步骤
- 统一资源协议:将所有SVG图片的引用地址从
http://改为https://,本地部署时优先使用相对路径引用资源,同时检查服务器的MIME类型配置,确保SVG资源返回类型正确。 - 修正样式配置:给图片样式补充固定尺寸和禁止收缩的规则,避免布局错乱:
.sample-item { width: 180px; /* 按你的标识实际比例调整 */ height: 125px; flex-shrink: 0; vertical-align: middle; padding-right: 20px; object-fit: contain; /* 保证SVG不变形 */ }
- 调整JS初始化时机与逻辑:不要在DOM加载完成后立刻执行滚动初始化,等所有图片资源加载完成后再运行尺寸计算和滚动逻辑,同时修复闭包变量问题,替换原有JS代码即可:
(function horizontalScrollingBanner() { var banners = document.getElementsByClassName('horizontal-scrolling-banner'); if (!banners || banners.length === 0) { return; } var pxPerSecond = 25; var allBannerImgs = banners[0].querySelectorAll('img'); var loadedNum = 0; function checkAndInit() { loadedNum++; if (loadedNum === allBannerImgs.length) { setUpElements(); scrollTheBanners(); } } allBannerImgs.forEach(function(img) { if (img.complete) { checkAndInit(); } else { img.addEventListener('load', checkAndInit); img.addEventListener('error', checkAndInit); // 加载失败也继续初始化,避免逻辑卡死 } }) window.addEventListener('resize', setUpElements); function setUpElements() { for (var i = 0; i < banners.length; i++) { var currentBanner = banners[i]; var helperWrapperClass = 'horizontal-scrolling-banner__helper-wrapper'; var currentHelperWrapper = currentBanner.querySelector('.' + helperWrapperClass); if (currentHelperWrapper) { var clones = currentHelperWrapper.querySelectorAll('[data-clone]'); Array.prototype.forEach.call(clones, function(clone) { clone.remove(); }); var oldChildrenCount = currentHelperWrapper.children.length; for (var j = 0; j < oldChildrenCount; j++) { currentBanner.appendChild(currentHelperWrapper.children[0]); } currentHelperWrapper.remove(); } var children = currentBanner.children; var bannerWidth = currentBanner.getBoundingClientRect().width; var minWidthToCoverBanner = (bannerWidth * 2) + children[0].getBoundingClientRect().width; var childrenWidth = Array.prototype.reduce.call(children, function(r, child) { return r + child.getBoundingClientRect().width; }, 0); var currentWidth = childrenWidth; do { Array.prototype.forEach.call(children, function(child) { var clone = child.cloneNode(); clone.setAttribute('aria-hidden', true); clone.dataset.clone = true; currentBanner.appendChild(clone); }); currentWidth += childrenWidth; } while (currentWidth < minWidthToCoverBanner); var transitionHelperWrapper = document.createElement('div'); transitionHelperWrapper.classList.add('horizontal-scrolling-banner__helper-wrapper'); var newChildrenCount = children.length; for (var k = 0; k < newChildrenCount; k++) { transitionHelperWrapper.appendChild(children[0]); } currentBanner.appendChild(transitionHelperWrapper); transitionHelperWrapper.dataset.childrenWidth = childrenWidth; } } function scrollTheBanners() { for (var i = 0; i < banners.length; i++) { var helperWrapper = banners[i].firstElementChild; var childrenWidth = Number(helperWrapper.dataset.childrenWidth); var offsetLeft = helperWrapper.offsetLeft; if (offsetLeft <= (childrenWidth * -1)) { helperWrapper.style.transitionDuration = '0s'; helperWrapper.style.left = '0px'; helperWrapper.style.removeProperty('transition-duration'); } else if (helperWrapper.style.left === '' || helperWrapper.style.left === '0px') { (function(wrapper, width) { setTimeout(function() { wrapper.style.transitionDuration = (width / pxPerSecond).toFixed() + 's'; wrapper.style.left = (width * -1) + 'px'; }, 0); })(helperWrapper, childrenWidth) } } requestAnimationFrame(scrollTheBanners); } })();
额外优化建议:如果想减少JS逻辑的不稳定性,可以直接用纯CSS实现无缝横向滚动,不需要动态克隆元素、计算尺寸,只需要把两份相同的标识内容放在滚动容器里,通过
@keyframes定义平移动画循环播放即可,兼容性和稳定性都更高。
内容的提问来源于stack exchange,提问作者La1sum
相关产品推荐
相关产品推荐

