Marquee не прокручивает все

У меня есть клиент, который использует область выделения, я знаю, я знаю, что это устаревший тег, и, честно говоря, его не следует использовать. Это его личный веб-сайт, и он какое-то время был моим клиентом, поэтому я решил реализовать выделение, но сделать это современным способом, без использования устаревших тегов. Я видел много разных решений для этого. Обычно я использую flexbox для чего-то подобного, потому что он не зависит от javascript или jQuery, но примеры выделения flexbox часто полагаются на жестко запрограммированную ширину для расчета скорости анимации ключевых кадров.

Короче говоря, я стремлюсь создать адаптивную область, но скорость не меняется в зависимости от того, сколько контента она прокручивает (я знаю, что об этом нужно много спрашивать). Мой клиент тоже пишет массу контента (я пыталась убедить его в обратном, но он все равно это делает).

Я собрал кое-что, что очень близко к решению. Он не использует flexbox, но хорошо меняет размер, не меняя скорость... Я уже довольно близок к тому, что мне нужно. В конце концов, мне не нужно использовать flexbox, поэтому, если все остальные флажки отмечены, меня это устраивает!

Это код, который я использую:

<div class = "pizza">
    <p class = "duck"><span class = "red">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span> <span class = "green">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span> <span class = "blue">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>.</p>
</div>

CSS:

.green {
    color: green;
}

.red {
    color: red;
}

.blue {
    color: blue;
}

.pizza {
    line-height: 60px;
    font-size: 16px;
    overflow: hidden;
    position: relative;
    white-space: nowrap;
}

p.duck {
  animation: scroll-left 20s linear infinite;
}

@keyframes scroll-left {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-100%, 0);
  }
}

p.duck:hover {
    animation-play-state: paused;
}

Рабочий пример: https://jsfiddle.net/L7kbhyg6/

Я добавил несколько интервалов, чтобы проблему было легче увидеть, но по сути не весь текст прокручивается. Я вижу красный, затем зеленый, затем шатер подпрыгивает и все начинается заново. Не знаю, как заставить его отображать весь мой контент.

Спасибо,
Джош

Я не понимаю, только с CSS и без javascript или jQuery?

Mister Jojo 29.06.2024 17:47

Я просто предпочитаю делать это только с помощью CSS, но если есть более простой способ с помощью JavaScript или jQuery, я тоже годюсь :-)

Josh Rodgers 29.06.2024 17:52

Я думаю, что в этом случае лучше всего использовать JS requestAnimationFrame.

Mister Jojo 29.06.2024 17:55

Не могли бы вы создать пример, я не знаю, как реализовать это решение.

Josh Rodgers 29.06.2024 17:57
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
1
4
69
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Чтобы обеспечить плавную прокрутку независимо от размера области просмотра или размера прокручиваемых элементов, имейте вторую копию.

Тогда преобразование происходит на -50%, а не на -100% (поэтому вторая копия попадает в левую часть, затем заменяется первой и так далее, благодаря чему она выглядит непрерывной).

Я не вижу необходимости в JS, если только вы не хотите сделать что-то более интересное и быстрое.

ОБНОВЛЕНИЕ: Хорошо, нам нужна постоянная скорость, независимо от того, что клиент помещает в область выделения.

Для этого вам понадобится пара строк JS, поскольку CSS не «знает» ширину всего текста.

Этот фрагмент позволяет CSS вычислить общую продолжительность одного цикла анимации. Это зависит от скорости, с которой вы хотите перемещать область выделения (постоянная для всех размеров области просмотра и количества текста), а также фактической ширины общей области выделения.

В p.duck установлен набор flex, justify-content, поэтому между всеми элементами имеется одинаковое расстояние и минимальная ширина, поэтому даже если клиент уменьшит количество символов до одного символа в каждом элементе, область выделения будет закрывать область просмотра.

function setUp() {
  const duck = document.querySelector('.duck');
  duck.style.setProperty('--w', window.getComputedStyle(duck).width.slice(0, -2));
}
window.onresize = setUp;
setUp();
.green {
  color: green;
}

.red {
  color: red;
}

.blue {
  color: blue;
}

.pizza {
  line-height: 60px;
  font-size: 16px;
  overflow: hidden;
  position: relative;
  white-space: nowrap;
}

p.duck {
  display: flex;
  justify-content: space-around;
  --s: 10s;
  /* time taken to travel  1000 px */
  animation: scroll-left calc(var(--s) * var(--w) / 2000) linear infinite;
  width: fit-content;
  min-width: 200vw;
}

@keyframes scroll-left {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-50%, 0);
  }
}

p.duck:hover {
  animation-play-state: paused;
}
<div class = "pizza">
  <p class = "duck">
    <span class = "red">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
    <span class = "green">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
    <span class = "blue">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
    <span class = "red">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
    <span class = "green">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
    <span class = "blue">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
  </p>
</div>

Мне нравится это решение, но проблема с этим ответом заключается в длине моего контента, он довольно длинный, поэтому скорость выделения очень высокая. Однако я могу регулировать скорость. Если я изменю содержимое прокрутки, скорость не должна измениться. Я не всегда могу быть рядом, когда область выделения обновляется, если используется небольшой объем текста, скорость области выделения снижается. Если используется большой объем текста, скорость выделения увеличивается.

Josh Rodgers 30.06.2024 05:30

Вам понадобится пара строк JS, чтобы получить постоянную скорость независимо от ширины текста, размера области просмотра и т. д. Я обновил фрагмент, чтобы показать, как это можно сделать.

A Haworth 30.06.2024 10:12

Спасибо за это! Мне тоже очень нравится этот вариант :-) спасибо за добавление JS, мне нравится минималистичный подход этого решения!

Josh Rodgers 01.07.2024 01:54

Могу ли я спросить, почему выделение необходимо повторять или дублировать? Я не понимаю цели этого, кроме добавления большего контента.

Josh Rodgers 01.07.2024 01:56

Я только что увидел ваш комментарий относительно повторяющихся элементов :-) Извините, я как-то это пропустил.

Josh Rodgers 01.07.2024 03:41
Ответ принят как подходящий

Я думаю, что в этом случае лучше всего использовать JS requestAnimationFrame. – Мистер Джоджо

Не могли бы вы создать пример, я не знаю, как реализовать это решение.

ну вот оно..
[Редактировать: изменено, чтобы позаботиться о маскировке изменения размера экрана]
[Обновлено: первая версия с уникальным ID => кодом только для одного «выделения» на странице]

(()=>  // IIFE closure  for <marquee> simulation on #pizza element
  {
  const
    pizza   = document.querySelector('#pizza')
  , pizza_p = document.querySelector('#pizza > p')
  , mov     = { pos   : pizza.offsetWidth
              , max   : -pizza_p.offsetWidth
              , pause : false 
              };
  pizza.addEventListener('mouseenter', ()=>
    { 
    mov.pause = true; 
    });
  pizza.addEventListener('mouseleave', ()=>
    { 
    mov.pause = false; 
    requestAnimationFrame(MarqueeMov); 
    });
 
  // auto launch
  pizza_p.style.left = `${mov.pos}px`;
  requestAnimationFrame(MarqueeMov);
  
  function MarqueeMov()
    {
    pizza_p.style.left = `${--mov.pos}px`;

    if ( mov.pos < mov.max 
      || mov.pos > pizza.offsetWidth // added to take care of screen resize
      )
      mov.pos = pizza.offsetWidth;

    if (!mov.pause)
      requestAnimationFrame(MarqueeMov);
    }
  }
)();
.green { color: green; }
.red   { color: red;   }
.blue  { color: blue;  }

#pizza {
  position    : relative;
  font-size   : 16px;
  height      : 32px;
  padding     : 0;
  overflow    : hidden;
  white-space : nowrap;
  cursor      : pointer;
  }
#pizza > p {
  margin   : 0;
  position : absolute;
  bottom   : 0;
  left     : 0;
  }
<div id = "pizza">
  <p>
    <span class = "red">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span> 
    <span class = "green">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span>
    <span class = "blue">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span>
  </p>
</div>

Вторая версия, позволяющая управлять несколькими полями «горизонтальной рамки» на одной странице.

(()=>  // IIFE closure  for <marquee> simulation for <div class = "JS-Marquee"> elements
  {
  const
    jsMarquees = [...document.querySelectorAll('.JS-Marquee')].map( jsMx =>
      { 
      let txtP = jsMx.querySelector('p');
      return ({ boxElm  : jsMx
              , boxLen  : jsMx.offsetWidth
              , txtElm  : txtP 
              , txtPEnd : -txtP.offsetWidth
              , txtPos  : jsMx.offsetWidth
              , pause   : false 
              });
      });
  jsMarquees.actives = jsMarquees.length;

  window.addEventListener('resize', ()=>
    {
    jsMarquees.forEach( jsM => { jsM.boxLen = jsM.boxElm.offsetWidth });
    });

  jsMarquees.forEach( jsM =>
    {
    jsM.boxElm.addEventListener('mouseenter',()=>
      {
      jsM.pause = true;
      --jsMarquees.actives;
      });
    jsM.boxElm.addEventListener('mouseleave',()=>
      {
      jsM.pause = false;
      ++jsMarquees.actives;
      if (jsMarquees.actives===1)
        requestAnimationFrame(MarqueeMoves); 
      });
    })

  // auto launch
  jsMarquees.forEach( jsM => { jsM.txtElm.style.left = `${jsM.txtPos}px`; })
  requestAnimationFrame(MarqueeMoves);

  function MarqueeMoves()
    {
    jsMarquees.forEach( jsM =>
      {
      if (jsM.pause) return;

      --jsM.txtPos;

      if ( jsM.txtPos > jsM.boxLen
        || jsM.txtPos < jsM.txtPEnd 
        ) 
        jsM.txtPos = jsM.boxLen;

      jsM.txtElm.style.left = `${jsM.txtPos}px`;
      });

    if (jsMarquees.actives)
      requestAnimationFrame(MarqueeMoves); 
    }

})();  // IIFE end of <marquee> JS simulation
.green { color: green; }
.red   { color: red;   }
.blue  { color: blue;  }

.JS-Marquee {
  position    : relative;
  font-size   : 16px;
  height      : 32px;
  padding     : 0;
  overflow    : hidden;
  white-space : nowrap;
  cursor      : pointer;
  }
.JS-Marquee > p {
  margin   : 0;
  position : absolute;
  bottom   : 0;
  left     : 0;
  }
<div class = "JS-Marquee">
  <p>
    <span class = "red">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span> 
    <span class = "green">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span>
    <span class = "blue">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span>
  </p>
</div>

<div class = "JS-Marquee">
  <p>
    <span class = "green">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span> 
    <span class = "blue">
      Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.
    </span>
  </p>
</div>

Я добавил решение, используя другую библиотеку. Я реализовал ваше решение, однако, когда размер браузера был изменен, мне пришлось ждать, пока прокрутка достигнет определенной позиции, прежде чем она отобразится. Мне удалось найти что-то, что возобновляло прокрутку при изменении размера браузера. Я знаю, что вы можете это сделать, но мне не хотелось просить об этом изменении. Если вы внесете это небольшое изменение, я хотел бы воздать вам должное за ответ :-) Я просто хотел опубликовать что-то, что может помочь кому-то еще, и это действительно решит проблему, с которой я столкнулся.

Josh Rodgers 30.06.2024 04:08

@JoshRodgers Хорошо, я сделаю это. Но у меня сейчас нет свободного времени, да и выборами здесь заниматься тоже надо (!)..., придется подождать несколько часов...

Mister Jojo 30.06.2024 11:19

@JoshRodgers Готово..

Mister Jojo 30.06.2024 17:46

Спасибо, я очень ценю, что вы внесли в него изменения, чтобы это работало для моего проекта!

Josh Rodgers 01.07.2024 01:51

Я провел дополнительное исследование и нашел пример с использованием библиотеки gsap JS.

CSS:

.green { color: green; }
.red   { color: red;   }
.blue  { color: blue;  }

#pizza {
    align-items: center;
    display: flex;
    height: 40px;
}

#pizza .wrap {
    overflow: hidden;
    white-space: nowrap;
    width: 100%;
}

#pizza .content {
    display: inline-block;
    white-space: nowrap;
}

/* Media */
@media screen and (min-width: 1000px) {
    #pizza {
        justify-content: center;
    }
}

HTML:

<div id = "pizza">
    <div class = "wrap">
        <div class = "content">
            <span class = "red">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
            <span class = "green">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>
            <span class = "blue">Start Lorem ipsum dolor sit amet consectetur adipisicing elit. Ut sed placeat aperiam quod nostrum itaque blanditiis soluta! Aliquid fuga molestias aut magni, pariatur doloremque, voluptas ipsa nobis ipsum voluptatibus end.</span>.
        </div>
    </div>
</div>

ЯС:

<script src = "https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.2/gsap.min.js"></script>

<script>
    document.addEventListener("DOMContentLoaded", function() {
        const marqueeContent = document.querySelector("#pizza .content");
        const marqueeContainer = document.querySelector("#pizza .wrap");
        let marqueeAnimation;

        function updateMarquee() {
            const contentWidth = marqueeContent.scrollWidth;
            const containerWidth = marqueeContainer.clientWidth;
            const totalWidth = contentWidth + containerWidth;
            const speedFactor = 100; // Speed factor for faster scrolling
            const duration = totalWidth / speedFactor;

            // Kill any existing animation
            if (marqueeAnimation) {
                marqueeAnimation.kill();
            }

            // Create a new animation
            marqueeAnimation = gsap.fromTo(marqueeContent, 
                { x: containerWidth },
                { x: -contentWidth, ease: "linear", repeat: -1, duration: duration }
            );
        }

        // Initial call
        updateMarquee();

        // Update the marquee on resize
        window.addEventListener("resize", updateMarquee);

        // Pause animation on hover
        marqueeContainer.addEventListener("mouseenter", () => gsap.globalTimeline.pause());
        marqueeContainer.addEventListener("mouseleave", () => gsap.globalTimeline.resume());
    });
</script>

Это дает мне возможность добавлять или уменьшать контент без ущерба для скорости. Этот также отзывчив и перезапускает прокрутку при изменении размера браузера.

Спасибо,
Джош

Другие вопросы по теме