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

HTML/CSS/JS文本左右滚动条故障:无法实现滚动效果求助

文本滚动条组件无法实现左右滚动的问题修复

我正在使用HTML、CSS和JavaScript开发一款文本滚动条组件,但遇到了技术问题:该滚动条无法实现左右滚动效果。以下是对应的实现代码:

JavaScript代码

document.addEventListener("DOMContentLoaded", function() {
  var element = document.getElementById("text-roller");
  var text_roller = new TextRoller(element);
  text_roller.start();
});

var TextRoller = (function() {

  //Helper functions
  function getWidth(element) {
    var rect = element.getBoundingClientRect();
    return rect.right - rect.left;
  }

  function TextRoller(box, speed = 20) {
    var inner_element = box.children && box.children[0] || null;
    if (!inner_element) throw "No child node found";

    inner_element.style.position = "relative";

    this.position = 0;
    this.speed = speed;
    this.box_width = getWidth(box);
    this.inner_element_width = getWidth(inner_element);
    this.box = box;
    this.inner_element = inner_element.cloneNode(true);
    setUpChildrens.call(this);
  }

  //Private functions
  function refreshWidths() {
    this.box_width = getWidth(this.box);
    this.inner_element_width = getWidth(this.box.children[0]);
  }

  function calculateNumElements() {
    return 1;
  }

  function setUpChildrens() {
    var qty = calculateNumElements.call(this);
    if (qty > this.box.children.length) {
      for (var i = this.box.children.length; i < qty; i++)
        this.box.appendChild(this.inner_element.cloneNode(true));
    } else if (qty < this.box.children.length) {
      for (var i = qty; i < this.box.children.length; i++)
        this.box.removeChild(this.box.lastChild);
    }
  }

  function nextFrame(delta) {
    var self = this;
    refreshWidths.call(this);
    setUpChildrens.call(this);
    Array.prototype.forEach.call(this.box.children, function(el) {
      el.style.left = -self.position + "px";
    });
    this.position += this.speed * delta / 300;
    if (this.position >= this.inner_element_width) this.position = this.position % this.inner_element_width;
  }

  TextRoller.prototype = {

    start: function() {
      this._running = true;
      var self = this;
      var last_time = null;
      var loop_func = function() {
        if (!self._running) return;
        var now = Date.now();
        var delta = last_time === null ? 0 : now - last_time;
        nextFrame.call(self, delta);
        last_time = now;
        window.requestAnimationFrame(loop_func);
      };
      window.requestAnimationFrame(loop_func);
    },

    stop: function() {
      this._running = false;
    }

  };

  return TextRoller;
})();

CSS代码

#text-roller {
  padding: 20px;
  position: relative;
  background-color: #88191d;
  color: black;
  white-space: nowrap;
  overflow: hidden;
}

.swiper-wrapper {
  display: -webkit-inline-box;
  text-align: center;
}

.swiper-wrapper div h2 {
  color: white !important;
}

HTML代码

<div id="text-roller">
  <div class="swiper-pointer-events">
    <div class="swiper-wrapper">
      <div style="width: 4% ;">
        <h2>Interaction</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Element</h2>
      </div>
      <div style="width: 6% ;">
        <h2>DIgital SOlution</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Strategy</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Branding</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Agency</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Interaction</h2>
      </div>
      <div style="width: 6% ;">
        <h2>DIgital SOlution</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Development</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Studio</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Strategy</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Branding</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Agency</h2>
      </div>
      <div style="width: 4% ;">
        <h2>typhography</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Design</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Interaction</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Element</h2>
      </div>
      <div style="width: 6% ;">
        <h2>DIgital SOlution</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Strategy</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Branding</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Agency</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Interaction</h2>
      </div>
      <div style="width: 6% ;">
        <h2>DIgital SOlution</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Development</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Studio</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Strategy</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Branding</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Agency</h2>
      </div>
      <div style="width: 4% ;">
        <h2>typhography</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Design</h2>
      </div>
      <div style="width: 4% ;">
        <h2>Interaction</h2>
      </div>
    </div>
  </div>
</div>

问题分析与修复方案

核心问题

  1. 滚动目标错误:当前代码操作的是#text-roller的直接子元素.swiper-pointer-events,但实际需要滚动的是内部的.swiper-wrapper——所有文本项都在这个容器里。
  2. 容器宽度计算错误:inner_element_width获取的是.swiper-pointer-events的宽度,而非.swiper-wrapper的总宽度,导致滚动重置逻辑失效。
  3. 无限滚动元素数量不足:calculateNumElements固定返回1,无法实现无缝滚动的循环效果。

修复步骤

1. 修正滚动目标元素

在TextRoller构造函数中,直接定位到实际需要滚动的.swiper-wrapper:

function TextRoller(box, speed = 20) {
  // 找到内部的swiper-wrapper作为滚动容器
  var inner_element = box.querySelector('.swiper-wrapper') || null;
  if (!inner_element) throw "No swiper-wrapper found";

  inner_element.style.position = "relative";

  this.position = 0;
  this.speed = speed;
  this.box_width = getWidth(box);
  this.inner_element_width = getWidth(inner_element);
  this.box = box;
  this.inner_element = inner_element.cloneNode(true);
  setUpChildrens.call(this);
}

2. 调整无限滚动元素数量计算

修改calculateNumElements,确保至少有2个副本实现无缝循环:

function calculateNumElements() {
  // 计算需要多少个副本才能覆盖容器宽度+一个完整内容宽度,实现无缝滚动
  return Math.ceil((this.box_width + this.inner_element_width) / this.inner_element_width);
}

3. 优化滚动逻辑

移除nextFrame中不必要的重复调用,并调整滚动重置逻辑:

function nextFrame(delta) {
  var self = this;
  Array.prototype.forEach.call(this.box.querySelectorAll('.swiper-wrapper'), function(el) {
    el.style.left = -self.position + "px";
  });
  this.position += this.speed * delta / 300;
  if (this.position >= this.inner_element_width) {
    // 滚动过一个完整宽度后,重置位置实现循环
    this.position -= this.inner_element_width;
  }
}

4. 调整CSS样式

确保.swiper-pointer-events不会限制子元素宽度:

.swiper-pointer-events {
  width: fit-content;
}

修复后效果

修改后,文本容器会持续向左滚动,当第一个副本完全移出视野后,第二个副本会无缝衔接,实现无限循环的左右滚动效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:07:05