Here is the JS code for the starter JS for the landing page, it includes a header stick on scroll, replace image with SVG, fade-in animation, number animation, parallax animation functions, and much more.
Vendors: libraries required
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css" integrity="sha512-tS3S5qG0BlhnQROyJXvNjeEM4UpMXHrQfTGmbQ1gKmelCxlSEBUaxhRBj/EFTzpbP4RVSrpEikbmdJobCvhE3g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- Custom CSS -->
<link rel="stylesheet" href="./assets/styles/landing.css" />
<!-- jQuery cdn -->
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<!-- GSAP -->
<script src="./assets/scripts/GSAP/gsap.min.js"></script>
<script src="./assets/scripts/GSAP/ScrollToPlugin.min.js"></script>
<script src="./assets/scripts/GSAP/ScrollTrigger.min.js"></script>
<script src="./assets/scripts/GSAP/ScrollSmoother.min.js"></script>
<script src="./assets/scripts/GSAP/TextPlugin.min.js"></script>
<script src="./assets/scripts/GSAP/SplitText.min.js"></script>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<!-- OWL Carousel -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js" integrity="sha512-bPs7Ae6pVvhOSiIcyUClR7/q2OAsRiovw4vAkX+zJbw3ShAeeqezq50RIIcIURq7Oa20rW2n2q+fyXBNcU9lrw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script>
<!-- Custom JS -->
<script src="./assets/scripts/landing.js"></script>
Landing.js
let vw = Math.max(document.documentElement.clientWidth);
let vh = Math.max(document.documentElement.clientHeight);
console.log( 'Viewport Dimension: ' + vw + ' X ' + vh);
// Register GSAP plugins
const initGSAP = (normalise = true) => {
gsap.registerPlugin(ScrollTrigger, ScrollToPlugin, ScrollSmoother, SplitText, TextPlugin);
ScrollTrigger.normalizeScroll(normalise);
}
// Page smooth scrolling
const enableScrollSmoother = () => {
ScrollSmoother.create({
smooth: 1,
effects: true,
smoothTouch: 0.1,
});
}
// Remove uwanted elements in mobile and desktop versions
const removeUnwantedElements = () => {
if(vw >= 992){
$('.mob-only').remove();
}else{
$('.desk-only').remove();
}
}
// Reload page if resized
const reloadPageIfAbove1200 = () => {
window.addEventListener("resize", function(){
if (window.innerWidth > 1200) {
location.reload();
}
});
}
// Fade animation - use selector: .fade-in
const initFadeInAnimation = () => {
const fadeElements = document.querySelectorAll(".fade-in");
fadeElements.forEach((element) => {
let classesArray = Array.from(element.classList);
let matchingClass = classesArray.find(className => className.startsWith("fade-in-delay-"));
let delayValue = 0;
if (matchingClass) {
delayValue = matchingClass.slice("fade-in-delay-".length);
}
gsap.fromTo(element, {
opacity: 0,
y: 100,
}, {
opacity: 1,
y: 0,
duration: 1,
delay: delayValue,
scrollTrigger: {
trigger: element,
start: "top bottom",
end: "bottom 0%",
toggleActions: "play none none reverse",
},
});
});
}
/* parallex effect */
const parallexTopAnim = () => {
var initialVal = 400;
var finalVal = -200;
if( vw < 768 ){
var initialVal = 200;
var finalVal = -100;
}
const parallexElements = document.querySelectorAll(".parallex-top");
parallexElements.forEach((element) => {
gsap.fromTo(element, {
y: initialVal,
}, {
y: finalVal,
scrollTrigger: {
trigger: element,
start: "top bottom",
end: "bottom top",
toggleActions: "play none none reverse",
scrub: 1,
},
});
});
}
const parallexBottomAnim = () => {
var initialVal = 0;
var finalVal = 200;
if( vw < 1400 ){
initialVal = 0;
finalVal = 125;
}
if( vw < 768 ){
initialVal = 0;
finalVal = 100;
}
const parallexElements = document.querySelectorAll(".parallex-bottom");
parallexElements.forEach((element) => {
gsap.fromTo(element, {
y: initialVal,
}, {
y: finalVal,
scrollTrigger: {
trigger: element,
start: "top bottom",
end: "bottom top",
toggleActions: "play none none reverse",
scrub: 1,
},
});
});
}
// Check section visible on viewport
const checkSectionActive = () => {
const sectionElements = document.querySelectorAll(".section");
sectionElements.forEach((element) => {
gsap.fromTo(element, {
},
{
scrollTrigger: {
trigger: element,
start: "top bottom",
end: "bottom top",
scrub: true,
toggleActions: "restart complete none none",
onEnter: function(){
$(element).addClass('section--active');
},
onEnterBack: function(){
$(element).addClass('section--active');
},
onLeave: function(){
$(element).removeClass('section--active');
},
onLeaveBack: function(){
$(element).removeClass('section--active');
},
},
});
});
}
// Check section visible on viewport
const checkViewportActive = () => {
const sectionElements = document.querySelectorAll(".check-viewport");
sectionElements.forEach((element) => {
gsap.fromTo(element, {
},
{
scrollTrigger: {
trigger: element,
start: "top bottom",
end: "bottom top",
scrub: true,
toggleActions: "restart complete none none",
onEnter: function(){
$(element).addClass('viewport-active');
},
onEnterBack: function(){
$(element).addClass('viewport-active');
},
onLeave: function(){
$(element).removeClass('viewport-active');
},
onLeaveBack: function(){
$(element).removeClass('viewport-active');
},
},
});
});
}
/* Check if all SVGs got loaded */
function executeAfterSVGsLoaded(className, callback) {
const svgs = document.querySelectorAll(`.${className}`);
let unloadedSVGs = svgs.length;
function handleSVGLoad() {
unloadedSVGs--;
if (unloadedSVGs === 0) {
// console.log('All SVGs with class "' + className + '" loaded successfully..');
callback();
}
}
for (const svg of svgs) {
if (svg.complete) {
handleSVGLoad();
} else {
svg.addEventListener("load", handleSVGLoad());
}
}
}
// equalizeHeights
const equalizeHeights = () => {
const parents = document.querySelectorAll('.equalize-columns');
parents.forEach(parent => {
const elements = parent.querySelectorAll('.equalize');
let maxHeight = 0;
// Reset heights to 'auto' before recalculating
elements.forEach(element => {
element.style.height = 'auto';
element.style.minHeight = 'auto';
});
// Find the maximum height for this parent
elements.forEach(element => {
maxHeight = Math.max(maxHeight, element.offsetHeight);
});
// Set all elements in this parent to the maximum height
elements.forEach(element => {
element.style.minHeight = maxHeight + 'px';
});
});
window.addEventListener('resize', function() {
equalizeHeights();
});
}
// Replace image tag with svg
const replaceWithSVG = () => {
let imgSelector = '.replaceWithSVG';
$(imgSelector).each(function(index, element) {
const totalElements = $(imgSelector).length;
let classes = $(element).attr('class');
if( $(element).attr('src') || $(element).attr('data-src') ){
let imgsrc = '';
if( $(element).attr('src') ){
imgsrc = $(element).attr('src');
}
if( $(element).attr('data-src') ){
imgsrc = $(element).attr('data-src');
}
fetch( imgsrc )
.then((response) => response.text())
.then((svgCode) => {
let tempElement = $(svgCode);
tempElement.addClass( classes );
$(element).after(tempElement);
$(element).remove();
if (index === totalElements - 1) {
setTimeout(function(){
executeAfterSVGsLoaded("replaceWithSVG", function () {
setTimeout(function(){
console.log( $(imgSelector).length + ' image/s replaced with SVG' );
runAfterSvgLoad();
}, 1000);
});
}, 1000);
}
})
.catch((error) => {
console.error("Error fetching SVG image:", error);
});
}else{
console.log( $(imgSelector).length + ' image/s already replaced with SVG' );
}
});
if($(imgSelector).length == 0){
setTimeout(function(){
console.log( $(imgSelector).length + ' image/s replaced with SVG' );
runAfterSvgLoad();
}, 1000);
}
}
// Smooth scroll to section on anchor click use id of section as src value
const smoothScrollToSection = () => {
// Smooth scroll to section
let headerHeight = $('.headerSec').height() - 50;
let targetPosition = 0;
if( window.location.hash && $(window.location.hash).length > 0) { // Checks # on URL
targetPosition = $(window.location.hash).offset().top - headerHeight;
gsap.to(window, {duration: 2, scrollTo: targetPosition });
}
$("a").click(function( event ) {
let href = $(this).attr('href');
let hash = href.substring(href.indexOf('#') + 1);
if(hash){
if ($('#' + hash).length) {
event.preventDefault();
$(this).closest('ul').find('a').removeClass('active');
$(this).closest('a').addClass('active');
targetPosition = $('#' + hash).offset().top - headerHeight;
gsap.to(window, {duration: 2, scrollTo: targetPosition });
}
}
});
}
// Let us know weather scroll is up or down
const handleScrollDirection = () => {
let lastScrollTop = 0;
// Function to handle the mouse scroll event and toggle the class
function handleMouseScroll() {
const elements = document.querySelectorAll('body'); // Replace 'your-target-class' with the class name of the elements you want to apply the class toggle to
const st = window.pageYOffset || document.documentElement.scrollTop;
elements.forEach(element => {
const scrollDirection = st > lastScrollTop ? 1 : -1;
// Toggle the class based on the scroll direction
if (scrollDirection === 1) {
element.classList.remove('upwards'); // Replace 'your-class' with the class name you want to add when scrolling downwards
element.classList.add('downwards');
} else if (scrollDirection === -1) {
element.classList.remove('downwards');
element.classList.add('upwards'); // Replace 'your-class' with the class name you want to remove when scrolling upwards
}
});
lastScrollTop = st <= 0 ? 0 : st; // Save the current scroll position for the next scroll event
}
// Add an event listener to the window to detect mouse scroll
window.addEventListener('scroll', handleMouseScroll);
}
// Menu script
const menuSecScripts = () => {
/* menu-btn */
$('.menu-btn, .menuSec__links a').click(function(){
$('.menuSec').addClass('animating');
$('body').toggleClass('no-scroll');
$('.menuSec').toggleClass('active');
setTimeout(function(){
$('.menuSec').removeClass('animating');
}, 1000)
})
}
// Toggle active header on scroll
const headerSection = () => {
// Toggle class on header on scroll
if ($(this).scrollTop() > 50 ) {
$('.headerSec').addClass('scrolling');
}else{
$('.headerSec').removeClass('scrolling');
}
$(window).scroll(function() {
if ($(this).scrollTop() > 50 ) {
$('.headerSec').addClass('scrolling');
}else{
$('.headerSec').removeClass('scrolling');
}
});
// Fixed Navbar
$(document).ready(function () {
let height = $('.top-header').height();
$('.headerSec').css('top', height + 'px');
});
$(window).on('scroll', function () {
let height = $('.top-header').height();
if ($(this).scrollTop() > height) {
$('.sticky-top').css('top', '0px');
$('.sticky-top nav').addClass('shadow-sm');
} else {
$('.sticky-top').css('top', height + 'px');
$('.sticky-top nav').removeClass('shadow-sm')
}
});
}
// Animate numbers
const animateNumbers = () => {
const numberElements = document.querySelectorAll(".animate-number");
numberElements.forEach((element) => {
gsap.fromTo(
element,
{},
{
scrollTrigger: {
trigger: element,
start: "top bottom",
end: "bottom top",
toggleActions: "play none none reverse",
onEnter: function () {
$(element)
.prop("Counter", 0)
.animate(
{
Counter: $(element).data("number"),
},
{
duration: 1500,
easing: "swing",
step: function (now) {
$(element).text(Math.ceil(now));
},
}
);
},
},
}
);
});
};
// Initialise all functions
const initAllFunctions = () => {
initGSAP(false);
//removeUnwantedElements();
//reloadPageIfAbove1200();
replaceWithSVG();
menuSecScripts();
headerSection();
if (vw >= 1200){
//enableScrollSmoother();
}
}
// Run animations after SVG load
const runAfterSvgLoad = () => {
smoothScrollToSection();
initFadeInAnimation();
checkSectionActive();
checkViewportActive();
parallexTopAnim();
parallexBottomAnim();
equalizeHeights();
// handleScrollDirection();
if(vw >= 992){
// Desktop specific animations
}else{
// Mobile specific animations
}
}
// Initialise Fuctions on Document Ready
$(document).ready(function() {
initAllFunctions();
});
/* Range Slider */
const rangeSlider = (slider_id) => {
var slider = document.getElementById(slider_id);
var sliderIndicator = slider.parentElement.querySelector('.slider__indicator');
sliderIndicator.style.width = slider.value + "%";
slider.addEventListener("input", function() {
var percent = (slider.value - slider.min) / (slider.max - slider.min) * 100;
sliderIndicator.style.width = percent + "%";
});
}
// Sort buttons
const sortButton = () => {
var sortButtonsAll = document.querySelector('.sortButtons__all');
sortButtonsAll.addEventListener('click', function(event) {
var target = event.target;
// Toggle classes based on the current state
if (!target.classList.contains('active-up') && !target.classList.contains('active-down')) {
// If the element has no class, remove all "active-up" and "active-down" classes from other divs
var allSortButtons = sortButtonsAll.children;
for (var i = 0; i < allSortButtons.length; i++) {
allSortButtons[i].classList.remove('active-up', 'active-down');
}
target.classList.add('active-up');
} else if (target.classList.contains('active-up')) {
// If the element has "active-up" class, change it to "active-down" class
target.classList.remove('active-up');
target.classList.add('active-down');
} else if (target.classList.contains('active-down')) {
// If the element has "active-down" class, change it to "" class (empty)
target.classList.remove('active-down');
}
});
}
// Datatable
const invokeDatatable1 = (id, searchid) => {
let datatable = new DataTable( id , {
responsive: true,
});
$(searchid).on('keyup', function() {
datatable.search(this.value).draw();
});
}