I'm having trouble getting my price ticker/slider to work properly on mobile devices. It works perfectly on desktop/laptop, but on mobile the ticker items just briefly appear and then disappear without sliding animation.
Here is a clip of the bug: Clip
Snippet provided below.
EDIT - Removing the display-flex
from the .ticker-container
resolves the issue, but causes the ticker items to go outside the div, resulting in the slider resetting before displaying all ticker items.
Below is an example of what I have implemented so far:
const tickerMap = {
'bitcoin': 'BTC',
'ethereum': 'ETH',
'binancecoin': 'BNB',
'bitcoin-cash': 'BCH',
'litecoin': 'LTC',
'ripple': 'XRP',
'chainlink': 'LINK',
'matic-network': 'MATIC',
'cardano': 'ADA',
'dogecoin': 'DOGE',
'shiba-inu': 'SHIB',
'solana': 'SOL',
'pepe': 'PEPE',
'avalanche-2': 'AVAX',
'polkadot': 'DOT'
};
async function fetchCryptoPrices() {
try {
const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum,ripple,solana,pepe,binancecoin,avalanche-2,chainlink,matic-network,bitcoin-cash,shiba-inu,litecoin,polkadot,cardano,dogecoin&vs_currencies=usd', {
mode: "cors"
});
//const responseData = '{"avalanche-2":{"usd":44.41},"binancecoin":{"usd":577.56},"bitcoin":{"usd":66572},"bitcoin-cash":{"usd":679.98},"cardano":{"usd":0.565032},"chainlink":{"usd":17.01},"dogecoin":{"usd":0.16979},"ethereum":{"usd":3239.5},"litecoin":{"usd":96.28},"matic-network":{"usd":0.867247},"pepe":{"usd":6.44e-06},"polkadot":{"usd":8.16},"ripple":{"usd":0.573485},"shiba-inu":{"usd":2.662e-05},"solana":{"usd":170.15}}'
const responseData = await response.text();
console.log('Response from server:', responseData);
const data = JSON.parse(responseData);
return data;
} catch (error) {
console.error('Error fetching cryptocurrency prices:', error);
return null;
}
}
async function createTickerItems() {
const ticker = document.getElementById('ticker');
ticker.innerHTML = ''; // Clear previous ticker items
const cryptoPrices = await fetchCryptoPrices();
if (cryptoPrices) {
Object.entries(cryptoPrices).forEach(([symbol, price]) => {
const tickerItem = document.createElement('div');
tickerItem.classList.add('ticker-item');
// Get the ticker symbol from the mapping, defaulting to the full name if not found
const tickerSymbol = tickerMap[symbol] || symbol.toUpperCase();
// Check if the symbol is one that needs custom decimal places
let formattedPrice;
if (symbol === 'shiba-inu' || symbol === 'pepe') {
// Format price for custom decimal places
formattedPrice = `$${price.usd.toFixed(6)}`;
} else {
// Default formatting for other tokens
formattedPrice = `$${price.usd.toFixed(2)}`;
}
tickerItem.textContent = `${tickerSymbol}: ${formattedPrice}`;
ticker.appendChild(tickerItem);
});
}
}
// Initialize ticker
createTickerItems();
.ticker-container {
overflow: hidden;
background-color: #111113;
border-top: 1px solid #222;
border-bottom: 1px solid #222;
color: #fff;
padding: 6px;
white-space: nowrap;
}
.ticker {
animation: marquee 20s linear infinite;
width: max-content;
}
.ticker-item {
margin-right: 20px;
background-color: #1a191f;
border-radius: 12px;
padding: 4px 12px;
font-size: 14px;
display: inline-block;
}
.ticker-item:last-of-type {
background-color: blue;
}
.ticker-item:first-of-type {
background-color: red;
}
@keyframes marquee {
0% {
transform:
}
100% {}
from {
transform: translateX(100dvw);
/* Use 100% of the viewport, not 100% of the element -> avoid waiting to long if you have many elements */
}
to {
transform: translateX(-100%);
}
}
@media(max-width:998px) {
.ticker {
animation: marquee 20s linear infinite !important;
}
.ticker-item {
margin-right: 10px !important;
}
}
<div class="ticker-container">
<div class="ticker" id="ticker">
<!-- Ticker items will be inserted here dynamically -->
</div>
</div>