Slideshow Project Using SCSS and JavaScript
Create an interactive slideshow using SCSS for styling and JavaScript for functionality. Learn to build responsive image carousels with smooth transitions.
Building a slideshow with SCSS and JavaScript combines the power of CSS preprocessors with interactive functionality. This tutorial shows you how to create a responsive, animated slideshow with clean SCSS architecture and minimal JavaScript for smooth image transitions.
We’ll create a simple but elegant slideshow with automatic rotation and manual controls. The SCSS handles all styling and animations, while JavaScript provides the interactive functionality.
// Slideshow container styles
.slideshow {
position: relative;
max-width: 800px;
margin: 0 auto;
overflow: hidden;
border-radius: 8px;
}
.slides {
display: flex;
transition: transform 0.5s ease-in-out;
}
.slide {
min-width: 100%;
height: 400px;
background-size: cover;
background-position: center;
}Navigation Controls
Create next/previous buttons and indicators using SCSS. We’ll position them absolutely over the slideshow and style them for clear interaction.
.btn-prev, .btn-next {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba(34, 34, 34, 0.7);
color: white;
border: none;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
font-size: 1.5rem;
transition: background 0.3s;
&:hover {
background: rgba(17, 171, 137, 0.9);
}
}
.btn-prev { left: 20px; }
.btn-next { right: 20px; }
.indicators {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
}
.indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
border: none;
cursor: pointer;
padding: 0;
&.active {
background: #11ab89;
}
}Complete SCSS Implementation
Here’s the complete SCSS code for our slideshow component, including responsive design and smooth animations.
// Slideshow variables
$primary-color: #11ab89;
$accent-color: #ff8000;
$dark-bg: #222222;
$transition-speed: 0.5s;
// Main slideshow container
.slideshow {
position: relative;
max-width: 800px;
margin: 2rem auto;
overflow: hidden;
border-radius: 12px;
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}
// Slides container
.slides {
display: flex;
transition: transform $transition-speed ease-in-out;
}
// Individual slide
.slide {
min-width: 100%;
height: 450px;
background-size: cover;
background-position: center;
display: flex;
align-items: flex-end;
padding: 2rem;
box-sizing: border-box;
&__caption {
background: rgba($dark-bg, 0.8);
color: white;
padding: 1rem 1.5rem;
border-radius: 6px;
max-width: 80%;
h3 {
color: $primary-color;
margin: 0 0 0.5rem 0;
font-size: 1.8rem;
}
p {
margin: 0;
opacity: 0.9;
}
}
}
// Navigation buttons
.btn-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
background: rgba($dark-bg, 0.7);
color: white;
border: none;
width: 50px;
height: 50px;
border-radius: 50%;
cursor: pointer;
font-size: 1.5rem;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:hover {
background: rgba($primary-color, 0.9);
transform: translateY(-50%) scale(1.1);
}
&:active {
transform: translateY(-50%) scale(0.95);
}
}
.btn-prev { left: 20px; }
.btn-next { right: 20px; }
// Indicators
.indicators {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 10;
}
.indicator {
width: 14px;
height: 14px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
border: 2px solid transparent;
cursor: pointer;
padding: 0;
transition: all 0.3s ease;
&:hover {
background: rgba(255, 255, 255, 0.8);
transform: scale(1.2);
}
&.active {
background: $primary-color;
border-color: white;
transform: scale(1.2);
}
}
// Responsive adjustments
@media (max-width: 768px) {
.slide {
height: 350px;
padding: 1rem;
&__caption {
max-width: 90%;
padding: 0.8rem 1rem;
h3 {
font-size: 1.8rem;
}
}
}
.btn-nav {
width: 40px;
height: 40px;
font-size: 1.2rem;
}
}JavaScript Functionality
The JavaScript handles slide transitions, automatic rotation, and user interactions. It’s minimal and focused on functionality.
class Slideshow {
constructor(container) {
this.container = container;
this.slides = container.querySelector('.slides');
this.slideElements = container.querySelectorAll('.slide');
this.indicators = container.querySelectorAll('.indicator');
this.prevBtn = container.querySelector('.btn-prev');
this.nextBtn = container.querySelector('.btn-next');
this.currentIndex = 0;
this.totalSlides = this.slideElements.length;
this.autoPlayInterval = null;
this.isHovered = false;
}
init() {
// Set up event listeners
this.prevBtn.addEventListener('click', () => this.prevSlide());
this.nextBtn.addEventListener('click', () => this.nextSlide());
// Indicator clicks
this.indicators.forEach((indicator, index) => {
indicator.addEventListener('click', () => this.goToSlide(index));
});
// Pause auto-play on hover
this.container.addEventListener('mouseenter', () => {
this.isHovered = true;
this.stopAutoPlay();
});
this.container.addEventListener('mouseleave', () => {
this.isHovered = false;
this.startAutoPlay();
});
// Start auto-play
this.startAutoPlay();
}
updateSlideshow() {
// Move slides container
this.slides.style.transform = `translateX(-${this.currentIndex * 100}%)`;
// Update indicators
this.indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === this.currentIndex);
});
}
nextSlide() {
this.currentIndex = (this.currentIndex + 1) % this.totalSlides;
this.updateSlideshow();
}
prevSlide() {
this.currentIndex = (this.currentIndex - 1 + this.totalSlides) % this.totalSlides;
this.updateSlideshow();
}
goToSlide(index) {
this.currentIndex = index;
this.updateSlideshow();
this.resetAutoPlay();
}
startAutoPlay() {
if (this.isHovered) return;
this.stopAutoPlay();
this.autoPlayInterval = setInterval(() => this.nextSlide(), 6000);
}
stopAutoPlay() {
if (this.autoPlayInterval) {
clearInterval(this.autoPlayInterval);
this.autoPlayInterval = null;
}
}
resetAutoPlay() {
if (this.isHovered) return;
this.stopAutoPlay();
this.startAutoPlay();
}
}
// Initialize slideshow when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
const slideshow = document.querySelector('.slideshow');
if (slideshow) {
const slider = new Slideshow(slideshow);
slider.init();
}
});HTML Structure
Here’s the complete HTML structure for our slideshow with sample images and captions.
<!DOCTYPE html>
<html lang=\\"en\\">
<head>
<meta charset=\\"UTF-8\\">
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\">
<title>SCSS & JavaScript Slideshow</title>
<link rel=\\"stylesheet\\" href=\\"style.css\\">
</head>
<body style=\\"background: #222222; padding: 2rem; min-height: 100vh;\\">
<div class=\\"slideshow\\">
<div class=\\"slides\\">
<div class=\\"slide\\" style=\\"background-image: url('img1.jpg');\\">
<div class=\\"slide__caption\\">
<h3>Beautiful Mountain View</h3>
<p>Experience the serenity of nature at its finest</p>
</div>
</div>
<div class=\\"slide\\" style=\\"background-image: url('img2.jpg');\\">
<div class=\\"slide__caption\\">
<h3>Ocean Sunset</h3>
<p>Witness stunning colors as day turns to night</p>
</div>
</div>
<div class=\\"slide\\" style=\\"background-image: url('img3.jpg');\\">
<div class=\\"slide__caption\\">
<h3>City Lights</h3>
<p>Urban landscapes come alive after dark</p>
</div>
</div>
</div>
<button class=\\"btn-nav btn-prev\\">‹</button>
<button class=\\"btn-nav btn-next\\">›</button>
<div class=\\"indicators\\">
<button class=\\"indicator active\\"></button>
<button class=\\"indicator\\"></button>
<button class=\\"indicator\\"></button>
</div>
</div>
<script src=\\"script.js\\"></script>
</body>
</html>Conclusion
This slideshow combines SCSS for elegant styling and JavaScript for smooth interactivity. The result is a responsive, user-friendly component that works across all devices. By separating concerns between styling (SCSS) and functionality (JavaScript), we maintain clean, maintainable code.