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

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回调执行时会拿到错误的变量引用,多横幅场景下滚动逻辑会完全错乱。

修复步骤

  1. 统一资源协议:将所有SVG图片的引用地址从http://改为https://,本地部署时优先使用相对路径引用资源,同时检查服务器的MIME类型配置,确保SVG资源返回类型正确。
  2. 修正样式配置:给图片样式补充固定尺寸和禁止收缩的规则,避免布局错乱:
.sample-item {
  width: 180px; /* 按你的标识实际比例调整 */
  height: 125px;
  flex-shrink: 0;
  vertical-align: middle;
  padding-right: 20px;
  object-fit: contain; /* 保证SVG不变形 */
}
  1. 调整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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 16:03:31