Reputation: 11
I've been trying to figure out how to get a marquee/ticker like effect with No Gaps. I found a website https://www.artpharmacy.com.au/ that uses this technique (the bottom of the page, "Buy Emilya's new Book").
I've tried to replicate what they have since this is exactly the effect I am going for.
The way they accomplished this, I believe is by creating two spans (with the same text in each span), and then used CSS animations. If someone could please explain how this is working, that would be great -- I copied over the code but I'd like to understand the logic behind it.
The primary issues I am having is that the:
The animation is very slow on my iphone (Safari). I am not sure why this is the case?
Sometimes the animation appears to be jerky or "flash". I've used linear and infinite properties and don't know what else to do to not cause this inconsistencies among the browsers?
I am also using mix-blend-mode on the scrolling text and wonder if they could also be contributing to the odd behavior. (Note: The div has a background image but I couldn't figure out how to add it in the snippet so just used background-color:purple)
Here is the code:
function makeMarquee() {
const title = 'Event: January 1-2, 2021, Zoom'
//use Array constructor to create an empty list with a length of 50 that is filled with the title.
//We can join all the contents of array using dash
const marqueeText = new Array(10).fill(title).join(' -- ')
//query Selector same as $ jquery, grab the span tags
const marquee = document.querySelector('.marquee span')
//set the text of span to be the marqueeText
marquee.innerHTML = marqueeText
// setTimeout(function () {marquee.style.animationName = 'moveLeft';},1000);
//create a clone of the div
var clone = marquee.cloneNode(true)
//add a class to this new div
clone.classList.add('marquee2')
//insert this new div after the first one
marquee.after(clone)
}
makeMarquee()
.section {
/*each section will take 100% of the height of browser */
min-height: 100vh;
/* Will help to vertically align container box */
display: flex;
position: relative;
}
/* Provide padding to left and right of section */
.section-pad {
padding-left: 5vw;
padding-right: 5vw;
}
.container {
/* Take the width of widest content box */
max-width: 780px;
/* Center our box horizontally and vertically using flex on .section */
margin: auto;
}
.intro {
background-image: url("intro-bg-min.png");
color: #fff;
background-color: purple;
}
.intro p {
font-size: 36px;
line-height: 1.2;
}
/* Utility class to center and cover background images */
.bg-cover {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.mix-difference {
/* our mix blend mode allows us to mix the current layer's style/colors with that of what's behind it to create some really cool effects */
mix-blend-mode: difference;
}
.marquee {
position: absolute;
top: 3vh;
left: 0;
width: 100%;
/*Each letter will be 5% of viewport width */
font-size: 5vw;
/* As tall as text */
line-height: 1;
text-transform: uppercase;
/*no scrollbars */
overflow: hidden;
white-space: nowrap;
/* Our span is inline by default, so change it to block */
}
.marquee span {
display: inline-block;
-webkit-animation: marquee 90s infinite linear;
animation: marquee 90s infinite linear;
}
@-webkit-keyframes marquee {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
}
@keyframes marquee {
0% {
/* -webkit-transform: translateX(0);
transform: translateX(0); */
transform: translate(0, 0);
}
100% {
/* -webkit-transform: translateX(-100%);
transform: translateX(-100%); */
transform: translate(-100%, 0);
}
}
/* give the span a margin left equal to one width of letter */
.marquee2 {
margin-left: 5vw;
animation-delay: 45s;
background-color: orange;
}
/* Before the span give it a dash to make it flow with the existing content */
.marquee2::before {
content: " -- ";
}
<section class="intro section section-pad bg-cover" id="intro">
<div class="copy container">
<div class="marquee mix-difference">
<!-- Here we add the title in multiple repeating times using javascript -->
<span>Event: January 1-2, 2020, Zoom</span>
</div>
<div class="mix-difference ">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tristique tellus finibus velit bibendum pulvinar. Pellentesque id congue tellus. Donec a urna at tortor sagittis vulputate sed id turpis. Donec a urna at tortor sagittis vulputate sed id turpis.
</p>
</div>
</div>
<a href="#day-1" class="js-scroll scroll-to scroll-to-intro"></a>
</section>
Upvotes: 0
Views: 4159
Reputation: 192
I was looking for a solution similar to this one as the only one I found uses the gsap library. But why use a library full of features if you only need one of them, right? Okay, since I found this question in the javascript section, I'll adapt the answer using only css to something more powerful using javascript. The solution below will replicate the items so that it suits your need. Take into account the max-width of the main element, otherwise the ticker will be based on a full hd resolution.
// HTML
<div class="ticker">
<div>
<mark>
<span>Info 01</span>
<span>Info 002</span>
<span>Info 0003</span>
<span>Info 00004</span>
</mark>
</div>
</div>
// CSS
html, body { margin: 0; padding: 0; }
.ticker {
width: 100%;
max-width: 1920px;
height: 80px;
margin: 0 auto;
overflow: hidden;
white-space: nowrap;
position: fixed;
bottom: 0;
height: 3.5rem;
background-color: #FFCA46;
}
.ticker > div {
opacity: 0;
display: inline-block;
margin-top: 5px;
}
.ticker.on > div {
opacity: 1;
animation: marquee 20s linear infinite;
}
.ticker > div mark {
background-color: transparent;
color: inherit;
font: inherit;
}
.ticker > div mark:first-child {
position: relative;
left: 0%;
}
.ticker.on > div mark:first-child {
animation: swap 20s linear infinite;
}
.ticker.on > div mark span {
display: inline-block;
padding: 0 1rem;
font-size: 2rem;
color: black;
font-weight: 800;
font-family: sans-serif;
}
/* Transition */
@keyframes marquee {
0% {
transform: translateX(0)
}
100% {
transform: translateX(-100%)
}
}
@keyframes swap {
0%, 50% {
left: 0%;
}
50.01%,
100% {
left: 100%;
}
}
// JS
const fullHD = 1920;
const tickers = document.body.querySelectorAll('.ticker');
tickers.forEach(ticker => {
const tickerStyle = window.getComputedStyle(ticker);
let maxWidth = tickerStyle.getPropertyValue('max-width');
if ( maxWidth.endsWith('px') ) { maxWidth = parseInt(maxWidth); } else { maxWidth = ( fullHD + 2 ); }
let mark = ticker.querySelector('mark');
markWidth = mark.getBoundingClientRect().width;
if ( ( markWidth > 0 ) && ( markWidth < maxWidth ) ){
let markInnerHTML = mark.innerHTML;
while ( markWidth < maxWidth ){
mark.innerHTML += markInnerHTML;
markWidth = markWidth + markWidth;
}
mark.parentElement.appendChild( mark.cloneNode(true) );
ticker.classList.add('on');
}
});
Upvotes: 0
Reputation: 21
Look at this code. I have tried to make it simpler, just with css.
I have added another loop to fix the whitespace issue. Let's see what you think.
https://codepen.io/bertofern/details/xxEpQGM
body { margin: 0; }
.ticker-wrap {
width: 100%;
height: 80px;
margin: 0 auto;
overflow: hidden;
white-space: nowrap;
position: fixed;
bottom: 0;
height: 3.5rem;
background-color: #FFCA46;
}
.ticker {
display: inline-block;
margin-top: 5px;
animation: marquee 20s linear infinite;
}
.item-collection-1 {
position: relative;
left: 0%;
animation: swap 20s linear infinite;
}
.item {
display: inline-block;
padding: 0 1rem;
font-size: 2rem;
color: black;
font-weight: 800;
font-family: sans-serif;
}
/* Transition */
@keyframes marquee {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
}
@keyframes swap {
0%, 50% {
left: 0%;
}
50.01%,
100% {
left: 100%;
}
}
<div class="ticker-wrap">
<div class="ticker">
<span class="item-collection-1">
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
</span>
<span class="item-collection-2">
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
<span class="item">Buy Emilya's New Book - Out Now! ➜</span>
</span>
</div>
<div>
I don't do any logic, I just use the code for each type of animation. To better understand how it works, I recommend that you look at the pages about animations and keyframes: https://www.w3schools.com/css/css3_animations.asp
https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes
Upvotes: 2