It can be useful for e-commerce sites needing to feature products, but I can see it working well for portfolio items, testimonials, or any collection of cards you want to present in a compact way.
1. The required HTML structure for the product carousel.
<main class="carousel-container" id="productCarousel" role="region" aria-labelledby="carouselHeading">
<h2 id="carouselHeading" class="visually-hidden">Featured Products Showcase - NovaSlider</h2>
<div class="loading-overlay" aria-hidden="true">
<div class="loader" role="status" aria-label="Loading featured products..."></div>
</div>
<div class="cards-wrapper" aria-live="polite"></div>
<button type="button" class="nav-arrow prev-arrow" aria-label="Previous Product Set" aria-controls="productCarousel">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" focusable="false" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
</svg>
</button>
<button type="button" class="nav-arrow next-arrow" aria-label="Next Product Set" aria-controls="productCarousel">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor" focusable="false" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</button>
<div class="pagination-dots" role="tablist" aria-label="Product Set Navigation"></div>
<div class="progress-container" aria-hidden="true">
<div class="progress-bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" aria-label="Carousel Progress"></div>
</div>
<div class="keyboard-hint" aria-hidden="true">
Use
<kbd class="key" title="Left Arrow Key">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" focusable="false" aria-hidden="true">
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
</svg>
</kbd>
and
<kbd class="key" title="Right Arrow Key">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" focusable="false" aria-hidden="true">
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
</svg>
</kbd>
to navigate
</div>
</main>
<div id="notification-anchor" aria-live="assertive" aria-atomic="true" style="position: fixed; z-index: 9999; bottom: 0; left: 0; width: 100%; display: flex; flex-direction: column; align-items: center; pointer-events: none;"></div> 2. Add the required JavaScript and CSS files to the page.
<link rel=”stylesheet” href=”card.css”>
<script src=”card.js” defer></script>
3. The Carousel is populated from a JavaScript array called PRODUCTS_DATA inside card.js. You’ll want to replace this with your own data. If your data schema is different, you’ll need to adjust the createProductCard function (or similar) within card.js that maps these properties to the card’s HTML.
const PRODUCTS_DATA = [
{ id: 1, imageSrc: 'https://picsum.photos/id/3/600/400', name: 'PURSHE Mini Projector, Portable HD Display for Home Cinema & Outdoor Movies', rating: 4.3, reviews: 61, sku: 'BOCRYVL494', price: '$41.32', category: { name: 'Electronics', class: 'electronics', iconSvg: ICONS.tv }, featured: false, actionButtons: [{label: ICONS.heart, aria: 'Add to favorites'}, {label: ICONS.eye, aria: 'View details'}] },
{ id: 2, imageSrc: 'https://picsum.photos/id/96/600/400', name: 'XBOX Wireless Controller - Electric Volt Special Edition with Textured Grips', rating: 4.8, reviews: 1205, sku: 'GAMEXCTRL01', price: '$59.99', category: { name: 'Gaming', class: 'gaming', iconSvg: ICONS.gamepad }, featured: true, actionButtons: [{label: ICONS.heart, aria: 'Add to favorites'}, {label: ICONS.eye, aria: 'View details'}] },
{ id: 3, imageSrc: 'https://picsum.photos/id/250/600/400', name: 'Polaroid Now i-Type Instant Camera - Retro Blue Design, Autofocus', rating: 4.5, reviews: 350, sku: 'POLAROIDNOW', price: '$99.99', category: { name: 'Photography', class: 'photo', iconSvg: ICONS.camera }, featured: false, actionButtons: [{label: ICONS.heart, aria: 'Add to favorites'}, {label: ICONS.eye, aria: 'View details'}] },
{ id: 4, imageSrc: 'https://picsum.photos/id/160/600/400', name: 'FitVerse Smart Watch Pro - Advanced Health & Fitness Tracker with GPS', rating: 4.6, reviews: 890, sku: 'SMTWCHPROX', price: '$129.50', category: { name: 'Wearables', class: 'wearables', iconSvg: ICONS.watch }, featured: false, actionButtons: [{label: ICONS.heart, aria: 'Add to favorites'}, {label: ICONS.eye, aria: 'View details'}] },
{ id: 5, imageSrc: 'https://picsum.photos/id/127/600/400', name: 'AuraSound Noise Cancelling Over-Ear Headphones - Onyx Black, Hi-Fi Audio', rating: 4.9, reviews: 2100, sku: 'AURAHDP005', price: '$199.00', category: { name: 'Audio', class: 'audio', iconSvg: ICONS.headphones }, featured: true, actionButtons: [{label: ICONS.heart, aria: 'Add to favorites'}, {label: ICONS.eye, aria: 'View details'}] }
]; 4. At the top of card.js, there’s a CONFIG object. This is where you can tweak some behaviors:
const CONFIG = {
animationDuration: 300,
swipeThreshold: 50,
touchMovementScaleFactor: 0.6,
initialLoadDelay: 600,
notificationTimeout: 3500,
debounceResizeTime: 150
}; 5. Customize the carousel by overriding the default CSS variables in the card.css.
:root {
--color-surface-primary: #ffffff;
--color-surface-secondary: #f9faff;
--color-surface-accent: #f0f6ff;
--color-surface-overlay: rgba(240, 246, 255, 0.65);
--color-text-primary: #1a202c;
--color-text-secondary: #4a5568;
--color-text-tertiary: #718096;
--color-text-on-accent: #ffffff;
--color-accent-primary: #0052cc;
--color-accent-primary-hover: #0041a3;
--color-accent-primary-darker: #003380;
--color-accent-secondary: #e6f0ff;
--color-accent-primary-rgb: 0, 82, 204;
--color-surface-accent-rgb: 240, 246, 255;
--color-rating: #ffb400;
--color-success: #34c759;
--color-featured-badge-bg-start: #ffdd57;
--color-featured-badge-bg-end: #ffb400;
--color-featured-badge-text: #4a3b00;
--color-featured-badge-icon: #9e7300;
--color-border-light: rgba(0, 27, 71, 0.1);
--color-border-focus: rgba(0, 102, 255, 0.6);
--color-border-interactive: rgba(0, 27, 71, 0.25);
--category-electronics-bg: #e0e7ff;
--category-electronics-text: #3730a3;
--category-gaming-bg: #dcfce7;
--category-gaming-text: #15803d;
--category-photo-bg: #fffbeb;
--category-photo-text: #b45309;
--category-wearables-bg: #dbeafe;
--category-wearables-text: #1d4ed8;
--category-audio-bg: #fee2e2;
--category-audio-text: #b91c1c;
--shadow-xs: 0 1px 2px rgba(26, 32, 44, 0.03);
--shadow-sm: 0 2px 4px rgba(26, 32, 44, 0.05);
--shadow-md: 0 6px 16px rgba(26, 32, 44, 0.07);
--shadow-lg: 0 12px 32px rgba(26, 32, 44, 0.09);
--shadow-xl: 0 24px 48px rgba(26, 32, 44, 0.1), 0 8px 16px rgba(26,32,44,0.06);
--shadow-focus-ring: 0 0 0 3px var(--color-border-focus);
--shadow-inset-light: inset 0 1px 2px rgba(0,0,0,0.06);
--shadow-inset-active: inset 0 2px 4px rgba(0,0,0,0.08);
--duration-micro: 100ms;
--duration-fast: 200ms;
--duration-normal: 350ms;
--duration-slow: 500ms;
--duration-extra-slow: 900ms;
--timing-ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--timing-ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
--timing-ease-in-out-cubic: cubic-bezier(0.65, 0, 0.35, 1);
--timing-soft-eio: cubic-bezier(0.76, 0, 0.24, 1);
--timing-anticipate: cubic-bezier(0.38, -0.2, 0.36, 1.4);
--timing-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--timing-elegant-snap: cubic-bezier(0.25, 0.1, 0.2, 1.25);
--font-family-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.375rem;
--line-height-tight: 1.25;
--line-height-normal: 1.5;
--line-height-relaxed: 1.75;
--letter-spacing-tight: -0.02em;
--letter-spacing-normal: 0;
--letter-spacing-wide: 0.025em;
--spacing-unit: 4px;
--space-xs: calc(var(--spacing-unit) * 1);
--space-sm: calc(var(--spacing-unit) * 2);
--space-md: calc(var(--spacing-unit) * 4);
--space-lg: calc(var(--spacing-unit) * 6);
--space-xl: calc(var(--spacing-unit) * 8);
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 16px;
--radius-xl: 20px;
--radius-full: 9999px;
--card-min-width: 280px;
--card-max-width: 320px;
--card-height: 510px;
--card-padding: var(--space-lg);
--card-margin-inline: var(--space-md);
--card-scale-inactive: 0.92;
--card-y-offset-inactive: 0px;
--card-opacity-inactive: 0.7;
--card-blur-inactive: 0.8px;
--card-saturate-inactive: 0.9;
--card-scale-active: 1.035;
--card-y-offset-active: -12px;
--card-active-border-width: 2.5px;
--carousel-perspective: 2000px;
--carousel-arrow-size: 44px;
--carousel-arrow-offset: calc(var(--carousel-arrow-size) / -2.2);
--focus-outline-offset: 2px;
} The post Responsive, Accessible Product Carousel – NovaSlider appeared first on CSS Script.
Resident Evil Requiem producer Masato Kumazawa has said Capcom sees the drama surrounding the DLSS…
The Pitt star Isa Briones has called out "f**king disrespectful" fans for yelling references while…
Pinecone has released Pinecone Nexus, a knowledge engine designed to move reasoning from retrieval to…
Enterprise Times met with Michal Sedzielewski co-founder of Voucherify at the MACH X event in…
Companies embarking on their first investments in Artificial Intelligence-led projects aim to use the new…
Two American cybersecurity professionals were sentenced to four years each in federal prison on April…
This website uses cookies.