Created
March 11, 2021 08:22
-
-
Save BloodCelebration/16887900a7b2eed254562a3ad552b315 to your computer and use it in GitHub Desktop.
Image slider with multiple controls and mobile swipe control (Javascript)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> | |
<link rel="stylesheet" href="css/style.css"> | |
<title>Slider</title> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="slider"> | |
<div class="box1 box"> | |
<div class="bg"></div> | |
<div class="details"> | |
<h1>I'm the first Box</h1> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing | |
elit. Integer lacinia dui lectus. Donec scelerisque ipsum | |
diam, ac mattis orci pellentesque eget. | |
</p> | |
<button>Check Now</button> | |
</div> | |
<div class="illustration"><div class="inner"></div></div> | |
</div> | |
<div class="box2 box"> | |
<div class="bg"></div> | |
<div class="details"> | |
<h1>I'm the second Box</h1> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing | |
elit. Integer lacinia dui lectus. Donec scelerisque ipsum | |
diam, ac mattis orci pellentesque eget. | |
</p> | |
<button>Check Now</button> | |
</div> | |
<div class="illustration"><div class="inner"></div></div> | |
</div> | |
<div class="box3 box"> | |
<div class="bg"></div> | |
<div class="details"> | |
<h1>I'm the third Box</h1> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing | |
elit. Integer lacinia dui lectus. Donec scelerisque ipsum | |
diam, ac mattis orci pellentesque eget. | |
</p> | |
<button>Check Now</button> | |
</div> | |
<div class="illustration"><div class="inner"></div></div> | |
</div> | |
<div class="box4 box"> | |
<div class="bg"></div> | |
<div class="details"> | |
<h1>I'm the fourth Box</h1> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing | |
elit. Integer lacinia dui lectus. Donec scelerisque ipsum | |
diam, ac mattis orci pellentesque eget. | |
</p> | |
<button>Check Now</button> | |
</div> | |
<div class="illustration"><div class="inner"></div></div> | |
</div> | |
<div class="box5 box"> | |
<div class="bg"></div> | |
<div class="details"> | |
<h1>I'm the fifth Box</h1> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing | |
elit. Integer lacinia dui lectus. Donec scelerisque ipsum | |
diam, ac mattis orci pellentesque eget. | |
</p> | |
<button>Check Now</button> | |
</div> | |
<div class="illustration"><div class="inner"></div></div> | |
</div> | |
</div> | |
<svg xmlns="http://www.w3.org/2000/svg" class="prev" width="56.898" height="91" viewBox="0 0 56.898 91"><path d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z" transform="translate(0 91) rotate(-90)" fill="#fff"/></svg> | |
<svg xmlns="http://www.w3.org/2000/svg" class="next" width="56.898" height="91" viewBox="0 0 56.898 91"><path d="M45.5,0,91,56.9,48.452,24.068,0,56.9Z" transform="translate(56.898) rotate(90)" fill="#fff"/></svg> | |
<div class="trail"> | |
<div class="box1 active">1</div> | |
<div class="box2">2</div> | |
<div class="box3">3</div> | |
<div class="box4">4</div> | |
<div class="box5">5</div> | |
</div> | |
</div> | |
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js"></script> | |
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CSSRulePlugin3.min.js"></script> | |
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.2/gsap.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.2/CSSRulePlugin.min.js"></script> --> | |
<script src="script.js"></script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Slider(all Slides in a container) | |
const slider = document.querySelector(".slider") | |
// All trails | |
const trail = document.querySelector(".trail").querySelectorAll("div") | |
// Transform value | |
let value = 0 | |
// trail index number | |
let trailValue = 0 | |
// interval (Duration) | |
let interval = 4000 | |
// Function to slide forward | |
const slide = (condition) => { | |
// CLear interval | |
clearInterval(start) | |
// update value and trailValue | |
condition === "increase" ? initiateINC() : initiateDEC() | |
// move slide | |
move(value, trailValue) | |
// Restart Animation | |
animate() | |
// start interal for slides back | |
start = setInterval(() => slide("increase"), interval); | |
} | |
// function for increase(forward, next) configuration | |
const initiateINC = () => { | |
// Remove active from all trails | |
trail.forEach(cur => cur.classList.remove("active")) | |
// increase transform value | |
value === 80 ? value = 0 : value += 20 | |
// update trailValue based on value | |
trailUpdate() | |
} | |
// function for decrease(backward, previous) configuration | |
const initiateDEC = () => { | |
// Remove active from all trails | |
trail.forEach(cur => cur.classList.remove("active")) | |
// decrease transform value | |
value === 0 ? value = 80 : value -= 20 | |
// update trailValue based on value | |
trailUpdate() | |
} | |
// function to transform slide | |
const move = (S, T) => { | |
// transform slider | |
slider.style.transform = `translateX(-${S}%)` | |
//add active class to the current trail | |
trail[T].classList.add("active") | |
} | |
const tl = gsap.timeline({defaults: {duration: 0.6, ease: "power2.inOut"}}) | |
tl.from(".bg", {x: "-100%", opacity: 0}) | |
.from("p", {opacity: 0}, "-=0.3") | |
.from("h1", {opacity: 0, y: "30px"}, "-=0.3") | |
.from("button", {opacity: 0, y: "-40px"}, "-=0.8") | |
// function to restart animation | |
const animate = () => tl.restart() | |
// function to update trailValue based on slide value | |
const trailUpdate = () => { | |
if (value === 0) { | |
trailValue = 0 | |
} else if (value === 20) { | |
trailValue = 1 | |
} else if (value === 40) { | |
trailValue = 2 | |
} else if (value === 60) { | |
trailValue = 3 | |
} else { | |
trailValue = 4 | |
} | |
} | |
// Start interval for slides | |
let start = setInterval(() => slide("increase"), interval) | |
// Next and Previous button function (SVG icon with different classes) | |
document.querySelectorAll("svg").forEach(cur => { | |
// Assign function based on the class Name("next" and "prev") | |
cur.addEventListener("click", () => cur.classList.contains("next") ? slide("increase") : slide("decrease")) | |
}) | |
// function to slide when trail is clicked | |
const clickCheck = (e) => { | |
// CLear interval | |
clearInterval(start) | |
// remove active class from all trails | |
trail.forEach(cur => cur.classList.remove("active")) | |
// Get selected trail | |
const check = e.target | |
// add active class | |
check.classList.add("active") | |
// Update slide value based on the selected trail | |
if(check.classList.contains("box1")) { | |
value = 0 | |
} else if (check.classList.contains("box2")) { | |
value = 20 | |
} else if (check.classList.contains("box3")) { | |
value = 40 | |
} else if (check.classList.contains("box4")) { | |
value = 60 | |
} else { | |
value = 80 | |
} | |
// update trail based on value | |
trailUpdate() | |
// transfrom slide | |
move(value, trailValue) | |
// start animation | |
animate() | |
// start interval | |
start = setInterval(() => slide("increase"), interval) | |
} | |
// Add function to all trails | |
trail.forEach(cur => cur.addEventListener("click", (ev) => clickCheck(ev))) | |
// Mobile touch Slide Section | |
const touchSlide = (() => { | |
let start, move, change, sliderWidth | |
// Do this on initial touch on screen | |
slider.addEventListener("touchstart", (e) => { | |
// get the touche position of X on the screen | |
start = e.touches[0].clientX | |
// (each slide with) the width of the slider container divided by the number of slides | |
sliderWidth = slider.clientWidth/trail.length | |
}) | |
// Do this on touchDrag on screen | |
slider.addEventListener("touchmove", (e) => { | |
// prevent default function | |
e.preventDefault() | |
// get the touche position of X on the screen when dragging stops | |
move = e.touches[0].clientX | |
// Subtract initial position from end position and save to change variabla | |
change = start - move | |
}) | |
const mobile = (e) => { | |
// if change is greater than a quarter of sliderWidth, next else Do NOTHING | |
change > (sliderWidth/4) ? slide("increase") : null; | |
// if change * -1 is greater than a quarter of sliderWidth, prev else Do NOTHING | |
(change * -1) > (sliderWidth/4) ? slide("decrease") : null; | |
// reset all variable to 0 | |
[start, move, change, sliderWidth] = [0,0,0,0] | |
} | |
// call mobile on touch end | |
slider.addEventListener("touchend", mobile) | |
})() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Colors | |
$b1cd: #500033; | |
$b1cl: #FF0077; | |
$b2cd: #000050; | |
$b2cl: #0033FF; | |
$b3cd: #00501D; | |
$b3cl: #00FF44; | |
$b4cd: #554D00; | |
$b4cl: #FF4E00; | |
$b5cd: #300050; | |
$b5cl: #8000FF; | |
$black: #000; | |
$white: #fff; | |
$grey: #B5B4B4; | |
////////// Mixin | |
// Generate different colors for slides | |
@mixin color_render($DC, $LC) { | |
background-color: $DC; | |
.illustration .inner { | |
background-color: $LC; | |
&::after, &::before{ background-color: rgba($LC, .4);} | |
} | |
button {background-color: $LC;} | |
} | |
*, | |
*:before, | |
*:after { | |
margin: 0; | |
padding: 0; | |
box-sizing: inherit; | |
} | |
html { | |
box-sizing: border-box; | |
font-family: 'Roboto', sans-serif; | |
font-size: 62.5%; | |
@media only screen and (max-width: 800px) { | |
font-size: 57%; | |
} | |
} | |
body { | |
background-color: #000; | |
color: $white; | |
padding: 8rem; | |
@media only screen and (max-width: 1000px) { | |
padding: 0; | |
} | |
} | |
.container { | |
position: relative; | |
overflow: hidden; | |
border-radius: 5rem; | |
@media only screen and (max-width: 1000px) { | |
border-radius: 0; | |
} | |
} | |
.slider { | |
display: flex; | |
width: 500%; | |
height: 55rem; | |
transition: all .25s ease-in; | |
// overflow-x: auto; | |
// scroll-snap-type: x mandatory; | |
// -webkit-overflow-scrolling: touch; | |
// scroll-behavior: smooth; | |
transform: translateX(0); | |
@media only screen and (max-width: 1000px) { | |
height: 100vh; | |
} | |
.box { | |
height: 100%; | |
width: 100%; | |
display: grid; | |
grid-template-columns: repeat(2, 1fr); | |
align-items: center; | |
overflow: hidden; | |
position: relative; | |
@media only screen and (max-width: 650px) { | |
grid-template-columns: 1fr; | |
grid-template-rows: repeat(2, 1fr); | |
} | |
.bg { | |
padding: 2rem; | |
background-color: rgba($black, .2); | |
width: 55%; | |
transform: skewX(7deg); | |
position: absolute; | |
height: 100%; | |
left: -10%; | |
padding-left: 20rem; | |
transform-origin: 0 100%; | |
@media only screen and (max-width: 800px) { | |
width: 65%; | |
} | |
@media only screen and (max-width: 650px) { | |
width: 100%; | |
left: 0; | |
bottom: 0; | |
height: 54%; | |
transform: skewX(0deg); | |
} | |
&::before { | |
content: ""; | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
left: 0; | |
top: 0; | |
background-color: inherit; | |
pointer-events: none; | |
transform: skewX(10deg); | |
@media only screen and (max-width: 650px) { | |
width: 120%; | |
bottom: 0; | |
transform: skewX(0deg); | |
} | |
} | |
} | |
.details { | |
padding: 5rem; | |
padding-left: 10rem; | |
z-index: 100; | |
grid-column: 1 / span 1; | |
grid-row: 1 / -1; | |
@media only screen and (max-width: 650px) { | |
grid-row: 2 / span 1; | |
grid-column: 1 / -1; | |
text-align: center; | |
padding:2rem; | |
transform: translateY(-9rem); | |
} | |
h1 { | |
font-size: 3.5rem; | |
font-weight: 500; | |
margin-bottom: .5rem; | |
} | |
p { | |
display: inline-block; | |
font-size: 1.3rem; | |
color: $grey; | |
margin-bottom: 2rem; | |
margin-right: 5rem; | |
@media only screen and (max-width: 800px) { | |
margin-right: 0; | |
} | |
} | |
button { | |
padding: 1rem 3rem; | |
color: $white; | |
border-radius: 2rem; | |
outline: none; | |
border: none; | |
cursor: pointer; | |
transition: all .3s ease; | |
&:hover {opacity: .8;} | |
&:focus { | |
outline: none; | |
border: none; | |
} | |
} | |
} | |
} | |
.box1 {@include color_render($b1cd, $b1cl)} | |
.box2 {@include color_render($b2cd, $b2cl)} | |
.box3 {@include color_render($b3cd, $b3cl)} | |
.box4 {@include color_render($b4cd, $b4cl)} | |
.box5 {@include color_render($b5cd, $b5cl)} | |
.illustration { | |
grid-column: 2 / -1; | |
grid-row: 1 / -1; | |
justify-self: center; | |
@media only screen and (max-width: 650px) { | |
grid-row: 1 / span 1; | |
grid-column: 1 / -1; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
div { | |
height: 25rem; | |
width: 18rem; | |
border-radius: 3rem; | |
background-color: $b1cl; | |
position: relative; | |
transform: skewX(-10deg); | |
@media only screen and (max-width: 800px) { | |
height: 20rem; | |
width: 15rem; | |
} | |
&::after, | |
&::before { | |
content: ""; | |
position: absolute; | |
height: 100%; | |
width: 100%; | |
border-radius: 3rem; | |
top: 0; | |
left: 0; | |
} | |
&::after {transform: translate(4rem, -1rem);} | |
&::before {transform: translate(2rem, -2rem);} | |
} | |
} | |
} | |
.prev, | |
.next, | |
.trail { | |
z-index: 10000; | |
position: absolute; | |
} | |
.prev, | |
.next { | |
width: 4rem; | |
cursor: pointer; | |
opacity: .2; | |
transition: all .3s ease; | |
@media only screen and (max-width: 650px) { | |
display: none; | |
} | |
&:hover { opacity: 1;} | |
} | |
.prev { | |
top: 50%; | |
left: 2%; | |
transform: translateY(-50%); | |
} | |
.next { | |
top: 50%; | |
right: 2%; | |
transform: translateY(-50%); | |
} | |
.trail { | |
bottom: 5%; | |
left: 50%; | |
transform: translateX(-50%); | |
width: 60%; | |
display: grid; | |
grid-template-columns: repeat(5, 1fr); | |
gap: 1rem; | |
text-align: center; | |
font-size: 1.5rem; | |
@media only screen and (max-width: 650px) { | |
width: 90%; | |
bottom: 13%; | |
} | |
div { | |
padding: 2rem; | |
border-top: 3px solid #fff; | |
cursor: pointer; | |
opacity: .3; | |
transition: all 0.3s ease; | |
&:hover {opacity: .6;} | |
@media only screen and (max-width: 650px) { | |
padding: 1rem; | |
} | |
} | |
} | |
.active { | |
opacity: 1 !important; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment