How to create Card Carousel | HTML, CSS, and JavaScript Project - Frontend everything
Hello Everyone 👋 Welcome to My New Blog. Today I made an Amazing Card Carousel with the help of HTML, CSS, and JavaScript Only! 😍
I am Piyush, Sharing About Web development Daily. You can also check out me at @frontendeverything.
Before starting the blog, you might think about where you can use this project in real-life-based projects. So it's an Amazing Card Carousel that you can use in your own blog project. So it will look attractive.
Let's start making these amazing Card Carousel Using HTML, CSS, and JavaScript.
Video of the project,
So that was the preview now let us start making the project 😄 First, we will code HTML then CSS, and also I have shared codepen ink to make it easier for you.
HTML 🎈( step - 1)
In HTML we have used header and div tags for the containers.
<script src="https://kit.fontawesome.com/48764efa36.js" crossorigin="anonymous"></script>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;600&display=swap" rel="stylesheet">
<h1>Select Your Path</h1>
<div id="album-rotator">
<div id="album-rotator-holder">
<a target="_top" class="album-item" href="https://twitter.com/smpnjn">
<span class="album-details">
<span class="icon"><i class="far fa-at"></i> smpnjn</span>
<span class="title">Click to</span>
<span class="subtitle">Follow</span>
<span class="subtext">On Twitter</span>
</span>
</a>
<a target="_top" class="album-item" href="https://fjolt.com/article/apple-cards-webl-gl-javascript">
<span class="album-details">
<span class="title">Read the</span>
<span class="subtitle">Tutorial</span>
<span class="subtext">View tutorial for this effect</span>
</span>
</a>
<a target="_top" class="album-item" href="https://twitter.com/smpnjn">
<span class="album-details">
<span class="title">Finally</span>
<span class="subtitle">We Go</span>
<span class="subtext">Some text to describe this item</span>
</span>
</a>
<a target="_top" class="album-item" href="https://twitter.com/smpnjn">
<span class="album-details">
<span class="title">And</span>
<span class="subtitle">One More</span>
<span class="subtext">Some text to describe this item</span>
</span>
</a>
<a class="album-item" href="https://twitter.com/smpnjn">
<span class="album-details">
<span class="title">And</span>
<span class="subtitle">Finally..</span>
<span class="subtext">Some text to describe this item</span>
</span>
</a>
</div>
</div>
<script id="noise" type="x-shader/x-fragment">
#define NUM_OCTAVES 5
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }
float rand(float n){return fract(sin(n) * 43758.5453123);}
float rand(vec2 n) {
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
float noise(float p){
float fl = floor(p);
float fc = fract(p);
return mix(rand(fl), rand(fl + 1.0), fc);
}
float noise(vec2 n) {
const vec2 d = vec2(0.0, 1.0);
vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
}
float snoise(vec2 v) {
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod289(i); // Avoid truncation effects in permutation
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}
const mat2 m2 = mat2(0.8,-0.6,0.6,0.8);
#define NB_OCTAVES 8
#define LACUNARITY 10.0
#define GAIN 0.5
float fbm(in vec2 p) {
float total = 0.0,
frequency = 1.0,
amplitude = 1.0;
for (int i = 0; i < NB_OCTAVES; i++) {
total += snoise(p * frequency) * amplitude;
frequency *= LACUNARITY;
amplitude *= GAIN;
}
return total;
}
</script>
<script id="vertex" type="x-shader/x-fragment">
uniform float u_time;
uniform float u_height;
uniform vec2 u_rand;
float xDistortion;
float yDistortion;
varying float vDistortion;
varying vec2 vUv;
void main() {
vUv = uv;
vDistortion = snoise(vUv.xx * 3. - vec2(u_time / u_rand.x, u_time / u_rand.x) + cos(vUv.yy) * u_rand.y) * u_height;
xDistortion = snoise(vUv.xx * 1.) * u_height * u_rand.x / 10.;
vec3 pos = position;
pos.z += (vDistortion * 55.);
pos.x += (xDistortion * 55.);
pos.y += (sin(vUv.y) * 55.);
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
</script>
<script id="fragment" type="x-shader/x-fragment">
vec3 rgb(float r, float g, float b) {
return vec3(r / 255., g / 255., b / 255.);
}
vec3 rgb(float c) {
return vec3(c / 255., c / 255., c / 255.);
}
uniform vec3 u_lowColor;
uniform vec3 u_highColor;
uniform float u_time;
varying vec2 vUv;
varying float vDistortion;
varying float xDistortion;
void main() {
vec3 highColor = rgb(u_highColor.r, u_highColor.g, u_highColor.b);
vec3 colorMap = rgb(u_lowColor.r, u_lowColor.g, u_lowColor.b);
colorMap = mix(colorMap, highColor, vDistortion);
gl_FragColor = vec4(colorMap, 1.);
}
</script>
After the HTML we will write CSS code!
Output till now
CSS🎈( step - 2)
body {
padding: 0;
margin: 0;
background: radial-gradient(circle at top left, #161231, #161231);
font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
padding: 4rem;
}
#album-rotator {
width: 1000px;
float: left;
white-space: nowrap;
overflow: hidden;
position: relative;
word-break: keep-all;
padding: 2rem 0;
}
#album-rotator-holder {
position: relative;
user-select: none;
will-change: transform;
/* transition: all 0.01s ease-out; */
/* transition: all 0.01s linear; */
}
div#album-rotator-holder {}
#album-rotator:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
background: linear-gradient(-90deg, #161231 5%, transparent 40%);
}
.album-item {
word-break: keep-all;
background: black;
box-shadow: 0 2px 30px rgba(0,0,0,0.5);
position: relative;
width: 250px;
-webkit-user-drag: none;
user-drag: none;
height: 300px;
user-select: none;
border-radius: 10px;
white-space: nowrap;
overflow: hidden;
display: inline-block;
margin: 0 3rem 0 0;
transition: all 0.2s ease-out;
transform: scale(1);
}
.album-item:hover {
transform: scale(1.02);
}
.album-details {
background: transparent;
position: absolute;
top: 0;
left: 0;
width: 100%;
text-shadow: 0 2px 15px rgba(0,0,0,0.5);
padding: 1rem;
white-space: initial;
float: left;
box-sizing: border-box;
color: white;
height: 100%;
font-size: 2.5rem;
font-weight: 600;
z-index: 99;
}
.title {
font-weight: 900;
display: inline-block;
width: 100%;
}
.subtitle {
font-weight: 100;
line-height: 1.25rem;
}
.subtext {
font-size: 1.1167rem;
position: absolute;
bottom: 0;
left: 0;
padding: 1.25rem 1rem;
width: 100%;
white-space: initial;
letter-spacing: 0;
box-sizing: border-box;
font-weight: 400;
}
.icon {
font-size: 1rem;
line-height: 1rem;
display: block;
padding: 0 0 0.5rem 0;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
h1 {
font-size: 2.5rem;
color: white;
margin: 0;
font-weight: 600;
text-shadow: 0 2px 10px rgba(0,0,0,0.2);
}
Now we have done the CSS coding as well, now we will do Javascript Coding and then see the final output.
JavaScript🎈( step - 3)
import * as THREE from 'https://cdn.skypack.dev/three@v0.122.0';
// Helper functions
const rgb = function(r, g, b) {
return new THREE.Vector3(r, g, b);
}
const loader = function(path, texture) {
return new Promise((resolve, reject) => {
let loader = new THREE.FileLoader();
if(typeof texture !== "undefined") {
loader = new THREE.TextureLoader();
}
loader.load(path, (item) => resolve(item));
})
}
const randomInteger = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// -- End Helper Functions
const config = {
individualItem: '.album-item', // class of individual item
carouselWidth: 1000, // in px
carouselId: '#album-rotator', // carousel selector
carouselHolderId: '#album-rotator-holder', // carousel should be <div id="carouselId"><div id="carouselHolderId">{items}</div></div>
colors: [
// Define colors for each item. If more items than colors, then first color will be used as default
// Format { low: rgb(), high: rgb() for each color }
{ low: rgb(0, 114, 255), high: rgb(48, 0, 255) },
{ low: rgb(236, 166, 15), high: rgb(233, 104, 0) },
{ low: rgb(43, 75, 235), high: rgb(213, 51, 248) },
{ low: rgb(175, 49, 49), high: rgb(123, 16, 16) }
]
}
// Async function for generating webGL waves
const createWave = async function(selector, colors) {
if(document.querySelectorAll(selector) !== null && document.querySelectorAll(selector).length > 0) {
// Import all the fragment and vertex shaders
const noise = document.getElementById('noise').textContent;
const fragment = document.getElementById('fragment').textContent
const vertex =document.getElementById('vertex').textContent
let i = 0;
// For each of the selector elements
document.querySelectorAll(selector).forEach(function(item) {
// Create a renderer
const newCanvas = document.createElement('canvas');
newCanvas.id = `canvas-${i}`;
item.appendChild(newCanvas);
const renderer = new THREE.WebGLRenderer({
powerPreference: "high-performance",
antialias: true,
alpha: true,
canvas: document.getElementById(`canvas-${i}`)
});
// Get el width and height
const elWidth = parseFloat(window.getComputedStyle(item).width);
const elHeight = parseFloat(window.getComputedStyle(item).height);
// Set sizes and set scene/camera
renderer.setSize( elWidth, elHeight );
renderer.setPixelRatio( window.devicePixelRatio );
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, elWidth / elHeight, 0.1, 1000 );
// Check on colors to use
let high = colors[0].high;
let low = colors[0].low;
if(typeof colors[i] !== "undefined") {
high = colors[i].high;
low = colors[i].low;
++i;
}
// And use the high color for the subtext.
if(item.querySelector('.subtext') !== null) {
item.querySelector('.subtext').style.background = `rgba(${high.x},${high.y},${high.z},0.75)`;
}
// Create a plane, and pass that through to our shaders
let geometry = new THREE.PlaneGeometry(600, 600, 100, 100);
let material = new THREE.ShaderMaterial({
uniforms: {
u_lowColor: {type: 'v3', value: low },
u_highColor: {type: 'v3', value: high },
u_time: {type: 'f', value: 0},
u_height: {type: 'f', value: 1},
u_rand: {type: 'f', value: new THREE.Vector2(randomInteger(6, 10), randomInteger(8, 10)) }
},
fragmentShader: noise + fragment,
vertexShader: noise + vertex,
});
// Create the mesh and position appropriately
let mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 0, -300);
mesh.material.needsUpdate = true;
scene.add(mesh);
// On hover effects for each item
let enterTimer, exitTimer;
item.addEventListener('mouseenter', function(e) {
if(typeof exitTimer !== "undefined") {
clearTimeout(exitTimer);
}
enterTimer = setInterval(function() {
if(mesh.material.uniforms.u_height.value >= 0.5) {
mesh.material.uniforms.u_height.value -= 0.05;
} else {
clearTimeout(enterTimer);
}
}, 10);
});
item.addEventListener('mouseleave', function(e) {
if(typeof enterTimer !== "undefined") {
clearTimeout(enterTimer);
}
exitTimer = setInterval(function() {
if(mesh.material.uniforms.u_height.value < 1) {
mesh.material.uniforms.u_height.value += 0.05;
} else {
clearTimeout(exitTimer);
}
}, 10);
});
// Render
renderer.render( scene, camera );
let t = 0;
// Animate
const animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
mesh.material.uniforms.u_time.value = t;
t = t + 0.02;
};
animate();
});
}
}
document.addEventListener("DOMContentLoaded", function(e) {
createWave(config.individualItem, config.colors);
// Get items
const el = document.querySelector(config.individualItem);
const elWidth = parseFloat(window.getComputedStyle(el).width) + parseFloat(window.getComputedStyle(el).marginLeft) + parseFloat(window.getComputedStyle(el).marginRight);
// Track carousel
let mousedown = false;
let movement = false;
let initialPosition = 0;
let selectedItem;
let currentDelta = 0;
document.querySelectorAll(config.carouselId).forEach(function(item) {
item.style.width = `${config.carouselWidth}px`;
});
document.querySelectorAll(config.carouselId).forEach(function(item) {
item.addEventListener('pointerdown', function(e) {
mousedown = true;
selectedItem = item;
initialPosition = e.pageX;
currentDelta = parseFloat(item.querySelector(config.carouselHolderId).style.transform.split('translateX(')[1]) || 0;
});
});
const scrollCarousel = function(change, currentDelta, selectedItem) {
let numberThatFit = Math.floor(config.carouselWidth / elWidth);
let newDelta = currentDelta + change;
let elLength = selectedItem.querySelectorAll(config.individualItem).length - numberThatFit;
if(newDelta <= 0 && newDelta >= -elWidth * elLength) {
selectedItem.querySelector(config.carouselHolderId).style.transform = `translateX(${newDelta}px)`;
} else {
if(newDelta <= -elWidth * elLength) {
selectedItem.querySelector(config.carouselHolderId).style.transform = `translateX(${-elWidth * elLength}px)`;
} else if(newDelta >= 0) {
selectedItem.querySelector(config.carouselHolderId).style.transform = `translateX(0px)`;
}
}
}
document.body.addEventListener('pointermove', function(e) {
if(mousedown == true && typeof selectedItem !== "undefined") {
let change = -(initialPosition - e.pageX);
scrollCarousel(change, currentDelta, document.body);
document.querySelectorAll(`${config.carouselId} a`).forEach(function(item) {
item.style.pointerEvents = 'none';
});
movement = true;
}
});
['pointerup', 'mouseleave'].forEach(function(item) {
document.body.addEventListener(item, function(e) {
selectedItem = undefined;
movement = false;
document.querySelectorAll(`${config.carouselId} a`).forEach(function(item) {
item.style.pointerEvents = 'all';
});
});
});
document.querySelectorAll(config.carouselId).forEach(function(item) {
let trigger = 0;
item.addEventListener('wheel', function(e) {
if(trigger !== 1) {
++trigger;
} else {
let change = e.deltaX * -3;
let currentDelta = parseFloat(item.querySelector(config.carouselHolderId).style.transform.split('translateX(')[1]) || 0;
scrollCarousel(change, currentDelta, item);
trigger = 0;
}
e.preventDefault();
e.stopImmediatePropagation();
return false;
});
});
});
Now we have done the JavaScript Coding, now let's see the final output. Also, I have shared the codepen link after the output so check that also.
Final Output
The codepen link is here for making your work easier!
.
If you found any value in this blog you can support me by buying me a coffee.
.
.
.
.
.
Thank You For Scrolling Till here 😊. If You gain any knowledge then do checkout me at @frontendeverything. I am Piyush 🎉 I provide Content related to programming, technology, web development Daily.
.
It's not working bro i don't know why but i put all the codes perfectly and line by line also . pls help me ........
ReplyDeleteYou've written a very detailed post regarding..... This information is useful to me and is also beneficial to people who...... I appreciate you providing this information.php developer
ReplyDeleteYou've written a very detailed post regarding..... This information is useful to me and is also beneficial to people who...... I appreciate you providing this information.digital signature
ReplyDelete