Custom slideshow with staggered transitions. Built in vanilla JS.
A Pen by vaniadimova on CodePen.
<div class="content-width"> | |
<div class="slideshow"> | |
<!-- Slideshow Items --> | |
<div class="slideshow-items"> | |
<div class="item"> | |
<div class="item-image-container"> | |
<img class="item-image" src="https://images.unsplash.com/photo-1578822043018-0fd3a0293a5b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjE2ODQ0fQ&auto=format&fit=crop&w=500&q=60" /> | |
</div> | |
<!-- Staggered Header Elements --> | |
<div class="item-header"> | |
<span class="vertical-part"><b>D</b></span> | |
<span class="vertical-part"><b>o</b></span> | |
<span class="vertical-part"><b>U</b></span> | |
<span class="vertical-part"><b>?</b></span> | |
</div> | |
<!-- Staggered Description Elements --> | |
<div class="item-description"> | |
<span class="vertical-part"> | |
<b>I am</b> | |
</span> | |
<span class="vertical-part"> | |
<b>the ocean.</b> | |
</span> | |
<span class="vertical-part"> | |
<b>My tears</b> | |
</span> | |
<span class="vertical-part"> | |
<b>are</b> | |
</span> | |
<span class="vertical-part"> | |
<b>a strong</b> | |
</span> | |
<span class="vertical-part"> | |
<b>current</b> | |
</span> | |
<span class="vertical-part"> | |
<b>pulling</b> | |
</span> | |
<span class="vertical-part"> | |
<b>me</b> | |
</span> | |
<span class="vertical-part"> | |
<b>to</b> | |
</span> | |
<span class="vertical-part"> | |
<b>you</b> | |
</span> | |
<span class="vertical-part"> | |
<b>.......</b> | |
</span> | |
<span class="vertical-part"> | |
<b>She</b> | |
</span> | |
<span class="vertical-part"> | |
<b>said</b> | |
</span> | |
<span class="vertical-part"> | |
<b>she was</b> | |
</span> | |
<span class="vertical-part"> | |
<b>a hurricane,</b> | |
</span> | |
<span class="vertical-part"> | |
<b>but</b> | |
</span> | |
<span class="vertical-part"> | |
<b>oh</b> | |
</span> | |
<span class="vertical-part"> | |
<b>how</b> | |
</span> | |
<span class="vertical-part"> | |
<b>I</b> | |
</span> | |
<span class="vertical-part"> | |
<b>LOVE</b> | |
</span> | |
<span class="vertical-part"> | |
<b>the</b> | |
</span> | |
<span class="vertical-part"> | |
<b>smell</b> | |
</span> | |
<span class="vertical-part"> | |
<b>of</b> | |
</span> | |
<span class="vertical-part"> | |
<b>the</b> | |
</span> | |
<span class="vertical-part"> | |
<b>rain</b> | |
</span> | |
</div> | |
</div> | |
<div class="item"> | |
<div class="item-image-container"> | |
<img class="item-image" src="https://images.unsplash.com/photo-1578815722759-276152ed9afb?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjExMDk0fQ&auto=format&fit=crop&w=500&q=60" /> | |
</div> | |
<!-- Staggered Header Elements --> | |
<div class="item-header"> | |
<span class="vertical-part"><b>S</b></span> | |
<span class="vertical-part"><b>e</b></span> | |
<span class="vertical-part"><b>e</b></span> | |
<span class="vertical-part"><b>L</b></span> | |
<span class="vertical-part"><b>o</b></span> | |
<span class="vertical-part"><b>v</b></span> | |
<span class="vertical-part"><b>e</b></span> | |
</div> | |
<!-- Staggered Description Elements --> | |
<div class="item-description"> | |
<span class="vertical-part"> | |
<b>SeeLove</b> | |
</span> | |
<span class="vertical-part"> | |
<b>If he</b> | |
</span> | |
<span class="vertical-part"> | |
<b>trully</b> | |
</span> | |
<span class="vertical-part"> | |
<b>loves you,</b> | |
</span> | |
<span class="vertical-part"> | |
<b>he will</b> | |
</span> | |
<span class="vertical-part"> | |
<b>love you</b> | |
</span> | |
<span class="vertical-part"> | |
<b>when you</b> | |
</span> | |
<span class="vertical-part"> | |
<b>are an</b> | |
</span> | |
<span class="vertical-part"> | |
<b>ocean breeze,</b> | |
</span> | |
<span class="vertical-part"> | |
<b>but also</b> | |
</span> | |
<span class="vertical-part"> | |
<b>when you</b> | |
</span> | |
<span class="vertical-part"> | |
<b>you are</b> | |
</span> | |
<span class="vertical-part"> | |
<b>a</b> | |
</span> | |
<span class="vertical-part"> | |
<b>summer</b> | |
</span> | |
<span class="vertical-part"> | |
<b>storm.</b> | |
</span> | |
<span class="vertical-part"> | |
<b>You are not</b> | |
</span> | |
<span class="vertical-part"> | |
<b>made to be</b> | |
</span> | |
<span class="vertical-part"> | |
<b>loved</b> | |
</span> | |
<span class="vertical-part"> | |
<b>in parts,</b> | |
</span> | |
<span class="vertical-part"> | |
<b>You were</b> | |
</span> | |
<span class="vertical-part"> | |
<b>meant</b> | |
</span> | |
<span class="vertical-part"> | |
<b>to be</b> | |
</span> | |
<span class="vertical-part"> | |
<b>loved</b> | |
</span> | |
<span class="vertical-part"> | |
<b>as a</b> | |
</span> | |
<span class="vertical-part"> | |
<b>whole.</b> | |
</span> | |
</div> | |
</div> | |
<div class="item"> | |
<div class="item-image-container"> | |
<img class="item-image" src="https://images.unsplash.com/photo-1518568814500-bf0f8d125f46?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60" /> | |
</div> | |
<!-- Staggered Header Elements --> | |
<div class="item-header"> | |
<span class="vertical-part"><b>B</b></span> | |
<span class="vertical-part"><b>e</b></span> | |
<span class="vertical-part"><b>l</b></span> | |
<span class="vertical-part"><b>i</b></span> | |
<span class="vertical-part"><b>e</b></span> | |
<span class="vertical-part"><b>v</b></span> | |
</div> | |
<!-- Staggered Description Elements --> | |
<div class="item-description"> | |
<span class="vertical-part"> | |
<b>Believe</b> | |
</span> | |
<span class="vertical-part"> | |
<b>You are filled</b> | |
</span> | |
<span class="vertical-part"> | |
<b>with doubt of the</b> | |
</span> | |
<span class="vertical-part"> | |
<b>magic</b> | |
</span> | |
<span class="vertical-part"> | |
<b>inside</b> | |
</span> | |
<span class="vertical-part"> | |
<b>you</b> | |
</span> | |
<span class="vertical-part"> | |
<b>but</b> | |
</span> | |
<span class="vertical-part"> | |
<b>it is</b> | |
</span> | |
<span class="vertical-part"> | |
<b>all I see.</b> | |
</span> | |
</div> | |
</div> | |
</div> | |
<div class="controls"> | |
<ul> | |
<li class="control" data-index="0"></li> | |
<li class="control" data-index="1"></li> | |
<li class="control" data-index="2"></li> | |
</ul> | |
</div> | |
</div> | |
</div> |
// Master DOManipulator v2 ------------------------------------------------------------ | |
const items = document.querySelectorAll('.item'), | |
controls = document.querySelectorAll('.control'), | |
headerItems = document.querySelectorAll('.item-header'), | |
descriptionItems = document.querySelectorAll('.item-description'), | |
activeDelay = .76, | |
interval = 5000; | |
let current = 0; | |
const slider = { | |
init: () => { | |
controls.forEach(control => control.addEventListener('click', (e) => { slider.clickedControl(e) })); | |
controls[current].classList.add('active'); | |
items[current].classList.add('active'); | |
}, | |
nextSlide: () => { // Increment current slide and add active class | |
slider.reset(); | |
if (current === items.length - 1) current = -1; // Check if current slide is last in array | |
current++; | |
controls[current].classList.add('active'); | |
items[current].classList.add('active'); | |
slider.transitionDelay(headerItems); | |
slider.transitionDelay(descriptionItems); | |
}, | |
clickedControl: (e) => { // Add active class to clicked control and corresponding slide | |
slider.reset(); | |
clearInterval(intervalF); | |
const control = e.target, | |
dataIndex = Number(control.dataset.index); | |
control.classList.add('active'); | |
items.forEach((item, index) => { | |
if (index === dataIndex) { // Add active class to corresponding slide | |
item.classList.add('active'); | |
} | |
}) | |
current = dataIndex; // Update current slide | |
slider.transitionDelay(headerItems); | |
slider.transitionDelay(descriptionItems); | |
intervalF = setInterval(slider.nextSlide, interval); // Fire that bad boi back up | |
}, | |
reset: () => { // Remove active classes | |
items.forEach(item => item.classList.remove('active')); | |
controls.forEach(control => control.classList.remove('active')); | |
}, | |
transitionDelay: (items) => { // Set incrementing css transition-delay for .item-header & .item-description, .vertical-part, b elements | |
let seconds; | |
items.forEach(item => { | |
const children = item.childNodes; // .vertical-part(s) | |
let count = 1, | |
delay; | |
item.classList.value === 'item-header' ? seconds = .015 : seconds = .007; | |
children.forEach(child => { // iterate through .vertical-part(s) and style b element | |
if (child.classList) { | |
item.parentNode.classList.contains('active') ? delay = count * seconds + activeDelay : delay = count * seconds; | |
child.firstElementChild.style.transitionDelay = `${delay}s`; // b element | |
count++; | |
} | |
}) | |
}) | |
}, | |
} | |
let intervalF = setInterval(slider.nextSlide, interval); | |
slider.init(); |
* { | |
box-sizing: border-box; | |
margin: 0; | |
padding: 0; | |
} | |
html, body { | |
width: 100%; | |
height: 100vh; | |
overflow: hidden; | |
background: #22222A; | |
font-family: 'Fira Mono', monospace; | |
-webkit-font-smoothing: antialiased; | |
font-size: .88rem; | |
color: #bdbdd5; | |
} | |
.content-width { | |
width: 86%; | |
height: 100vh; | |
margin: 0 auto; | |
} | |
.slideshow { | |
position: relative; | |
width: 100%; | |
height: 100vh; | |
display: flex; | |
flex-direction: column; | |
justify-content: space-around; | |
} | |
.slideshow-items { | |
position: relative; | |
width: 100%; | |
height: 300px; | |
} | |
.item { | |
position: absolute; | |
width: 100%; | |
height: auto; | |
} | |
.item-image-container { | |
position: relative; | |
width: 42%; | |
} | |
.item-image-container::before { | |
content: ''; | |
position: absolute; | |
top: -1px; | |
left: 0; | |
width: 101%; | |
height: 101%; | |
background: #22222A; | |
opacity: 0; | |
z-index: 1; | |
} | |
.item-image { | |
position: relative; | |
width: 100%; | |
height: auto; | |
opacity: 0; | |
display: block; | |
/* transition: property name | duration | timing-function | delay */ | |
transition: opacity .3s ease-out .45s; | |
} | |
.item.active .item-image { | |
opacity: 1; | |
} | |
.item.active .item-image-container::before { | |
opacity: .8; | |
} | |
.item-description { | |
position: absolute; | |
top: 182px; | |
right: 0; | |
width: 50%; | |
padding-right: 4%; | |
line-height: 1.8; | |
} | |
/* Staggered Vertical Items ------------------------------------------------------*/ | |
.item-header { | |
position: absolute; | |
top: 150px; | |
left: -1.8%; | |
z-index: 100; | |
} | |
.item-header .vertical-part { | |
margin: 0 -4px; | |
font-family: 'Montserrat', sans-serif; | |
-webkit-font-smoothing: auto; | |
font-size: 7vw; | |
color: #fff; | |
} | |
.vertical-part { | |
overflow: hidden; | |
display: inline-block; | |
} | |
.vertical-part b { | |
display: inline-block; | |
transform: translateY(100%); | |
} | |
.item-header .vertical-part b { | |
transition: .5s; | |
} | |
.item-description .vertical-part b { | |
transition: .21s; | |
} | |
.item.active .item-header .vertical-part b { | |
transform: translateY(0); | |
} | |
.item.active .item-description .vertical-part b { | |
transform: translateY(0); | |
} | |
/* Controls ----------------------------------------------------------------------*/ | |
.controls { | |
position: relative; | |
text-align: right; | |
z-index: 1000; | |
} | |
.controls ul { | |
list-style: none; | |
} | |
.controls ul li { | |
display: inline-block; | |
width: 10px; | |
height: 10px; | |
margin: 3px; | |
background:#bdbdd5;; | |
cursor: pointer; | |
} | |
.controls ul li.active { | |
background:#6a6a77;; | |
} |
<link href="https://fonts.googleapis.com/css?family=Fira+Mono|Montserrat:800" rel="stylesheet" /> |
Custom slideshow with staggered transitions. Built in vanilla JS.
A Pen by vaniadimova on CodePen.