Free Photography Website Template: HTML, Tailwind & GSAP (2026)

Faraz

By Faraz -

Download a free, high-performance photography website template built with HTML, Tailwind CSS, and GSAP animations. Perfect for portfolios. Get the code now!


free-photography-website-template-html-tailwind-and-gsap-2026.webp

Table of Contents

  1. Project Introduction
  2. HTML Code
  3. CSS Code
  4. JavaScript Code
  5. Conclusion
  6. Preview

Every photographer needs a digital home. Your photos are masterpieces, so your website should be one too. But building a site from scratch can feel scary if you don't code every day.

In this guide, I will share a free code snippet to build a modern, animated photography homepage. We aren't just using plain HTML; we are powering it up with Tailwind CSS for styling and GSAP (GreenSock) for those smooth, professional animations that make clients say "Wow."

Prerequisites: Before we start, make sure you have:

  • A basic code editor (like VS Code).
  • Basic knowledge of HTML and CSS.
  • An internet connection (to load the libraries via CDN).

Let's dive into the code!

Source Code

Step 1 (HTML Code):

First, we set up the skeleton of our website. We will include the CDN links for Tailwind CSS, Phosphor Icons (for cool icons), jQuery, and GSAP right in the <head>.

The layout includes a Navbar, a Hero Section (the first thing people see), and a Gallery Grid to show off your work.

Step 2 (CSS Code):

The beauty of this template is that 95% of the CSS is already written inside the HTML classes using Tailwind.

  • bg-brand-accent: Sets a dark, premium background.
  • hover:scale-110: Creates a smooth zoom effect on images when you hover.
  • mix-blend-difference: Makes sure the navbar is visible on both light and dark backgrounds.

We added a tiny block of custom CSS in the <head> just to import the Google Fonts (Oswald for elegance and Inter for readability) and set the initial state for our animations.

@tailwind base;
@tailwind components;
@tailwind utilities;

/* Global Focus Reset */
*:focus {
    outline: none !important;
}

body {
    background-color: #0a0a0a;
    color: #f5f5f5;
    cursor: none;
    /* Hiding default cursor for custom one */
    overflow-x: hidden;
}

/* FORCE CURSOR HIDDEN ON INTERACTIVE ELEMENTS */
a,
button,
input,
[type="button"],
[type="submit"],
.hover-trigger {
    cursor: none !important;
}

/* Custom Cursor Base Styles */
.cursor-dot,
.cursor-outline {
    position: fixed;
    top: 0;
    left: 0;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    z-index: 9999;
    pointer-events: none;
    transition: width 0.2s, height 0.2s, background-color 0.2s, border-color 0.2s;
}

/* White Mode */
.cursor-dot {
    width: 8px;
    height: 8px;
    background-color: white;
}

.cursor-outline {
    width: 40px;
    height: 40px;
    border: 1px solid rgba(255, 255, 255, 0.5);
}

/* Hover State on Dark Background */
body:hover .cursor-outline.hovered {
    width: 80px;
    height: 80px;
    background-color: rgba(255, 255, 255, 0.05);
    border-color: transparent;
}

/* Dark Mode (For White Backgrounds) */
.cursor-dot.dark {
    background-color: #0a0a0a !important;
}

.cursor-outline.dark {
    border-color: rgba(0, 0, 0, 0.5) !important;
}

/* Hover State on Light Background */
body:hover .cursor-outline.dark.hovered {
    width: 80px;
    height: 80px;
    background-color: rgba(0, 0, 0, 0.05) !important;
    border-color: transparent !important;
}

/* Precise Hamburger Animation */
.hamburger {
    width: 30px;
    height: 20px;
    position: relative;
    transform: rotate(0deg);
    transition: .5s ease-in-out;
    cursor: pointer;
}

.hamburger span {
    display: block;
    position: absolute;
    height: 2px;
    width: 100%;
    background: white;
    border-radius: 9px;
    opacity: 1;
    left: 0;
    transform: rotate(0deg);
    transition: .25s ease-in-out;
}

.hamburger span:nth-child(1) {
    top: 0px;
}

.hamburger span:nth-child(2) {
    top: 9px;
}

.hamburger span:nth-child(3) {
    top: 18px;
}

.hamburger.active span:nth-child(1) {
    top: 9px;
    transform: rotate(135deg);
}

.hamburger.active span:nth-child(2) {
    opacity: 0;
    left: -60px;
}

.hamburger.active span:nth-child(3) {
    top: 9px;
    transform: rotate(-135deg);
}

/* Hero Styles */
.hero-text-stroke {
    -webkit-text-stroke: 1px rgba(255, 255, 255, 0.15);
    color: transparent;
}

.glass-panel {
    background: rgba(255, 255, 255, 0.03);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.1);
}

.blend-difference {
    mix-blend-mode: difference;
}

/* Animated Grain Background */
.bg-grain {
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
}

/* Image Hover Distortion (Simulated via scale/filter) */
.portfolio-item {
    position: relative;
    overflow: hidden;
}

.portfolio-item img {
    transition: transform 0.7s cubic-bezier(0.2, 1, 0.3, 1), filter 0.5s;
}

.portfolio-item:hover img {
    transform: scale(1.1);
    filter: grayscale(100%) contrast(120%);
}

.portfolio-overlay {
    background: linear-gradient(to top, black, transparent);
}

/* Scrollbar Hide */
::-webkit-scrollbar {
    width: 8px;
}

::-webkit-scrollbar-track {
    background: #0a0a0a;
}

::-webkit-scrollbar-thumb {
    background: #333;
}

::-webkit-scrollbar-thumb:hover {
    background: #555;
}

.outlined-text {
    -webkit-text-stroke: 1px rgba(255, 255, 255, 0.3);
    color: transparent;
    transition: all 0.3s ease;
}

.outlined-text:hover {
    -webkit-text-stroke: 0px;
    color: #FF3B30;
}

/* Footer */
.footer-link {
    position: relative;
}

.footer-link::after {
    content: '';
    position: absolute;
    bottom: -2px;
    left: 0;
    width: 0%;
    height: 2px;
    background: #FF3B30;
    transition: width 0.4s ease;
}

.footer-link:hover::after {
    width: 100%;
}

/* Mobile Menu Styles */
.mobile-link {
    position: relative;
    display: inline-block;
}

.mobile-link::before {
    content: attr(data-index);
    position: absolute;
    top: 0;
    left: -30px;
    font-size: 0.8rem;
    font-family: 'Inter', sans-serif;
    color: #FF3B30;
    opacity: 0;
    transform: translateX(10px);
    transition: all 0.3s ease;
}

.mobile-link:hover::before {
    opacity: 1;
    transform: translateX(0);
} 

Step 3 (JavaScript Code):

Now for the magic. We will use GSAP to make the text float up when the page loads, and ScrollTrigger to make images appear smoothly as the user scrolls down.

$(document).ready(function () {
  gsap.registerPlugin(ScrollTrigger);

  // 1. Custom Cursor Logic
  const cursorDot = $('.cursor-dot');
  const cursorOutline = $('.cursor-outline');

  // Mouse move handler
  $(window).on('mousemove', function (e) {
    const posX = e.clientX;
    const posY = e.clientY;
    updateCursor(posX, posY);

    // Smart Cursor Color Switching (For White Backgrounds)
    // Check if hovering over a light section
    const target = $(document.elementFromPoint(e.clientX, e.clientY));
    if (target && target.closest('.light-section').length > 0) {
      cursorDot.addClass('dark');
      cursorOutline.addClass('dark');
    } else {
      cursorDot.removeClass('dark');
      cursorOutline.removeClass('dark');
    }
  });

  // Touch move handler (New for mobile)
  $(window).on('touchmove', function (e) {
    const touch = e.touches[0];
    const posX = touch.clientX;
    const posY = touch.clientY;
    updateCursor(posX, posY);
  });

  function updateCursor(x, y) {
    cursorDot.css({
      left: x + 'px',
      top: y + 'px',
    });
    cursorOutline.css({
      left: x + 'px',
      top: y + 'px',
    });
  }

  // Hover state for cursor
  $('.hover-trigger, a, button')
    .on('mouseenter', function () {
      cursorOutline.addClass('hovered');
    })
    .on('mouseleave', function () {
      cursorOutline.removeClass('hovered');
    });

  // 2. Navbar Hamburger Animation
  $('.hamburger').click(function () {
    $(this).toggleClass('active');
    const mobileMenu = $('.mobile-menu');

    if ($(this).hasClass('active')) {
      mobileMenu
        .removeClass('invisible opacity-0')
        .addClass('visible opacity-100');

      // Staggered Text Reveal for Mobile Menu
      gsap.fromTo(
        '.menu-item',
        { y: 50, opacity: 0 },
        {
          y: 0,
          opacity: 1,
          stagger: 0.1,
          duration: 0.8,
          ease: 'power3.out',
          delay: 0.2,
        }
      );

      // Reveal details at bottom
      gsap.fromTo(
        '.menu-details',
        { y: 30, opacity: 0 },
        { y: 0, opacity: 1, duration: 0.8, ease: 'power3.out', delay: 0.5 }
      );

      $('body').css('overflow', 'hidden');
    } else {
      mobileMenu
        .removeClass('visible opacity-100')
        .addClass('invisible opacity-0');
      $('body').css('overflow', 'auto');
    }
  });

  // Resize Handler: Close mobile menu if resizing to desktop
  $(window).resize(function () {
    if ($(window).width() > 768) {
      $('.hamburger').removeClass('active');
      $('.mobile-menu')
        .removeClass('visible opacity-100')
        .addClass('invisible opacity-0');
      $('body').css('overflow', 'auto');
    }
  });

  // Close mobile menu when a link is clicked
  $('.mobile-link').click(function () {
    $('.hamburger').removeClass('active');
    $('.mobile-menu')
      .removeClass('visible opacity-100')
      .addClass('invisible opacity-0');
    $('body').css('overflow', 'auto');
  });

  // 3. Navbar Color Change on Scroll
  $(window).scroll(function () {
    if ($(this).scrollTop() > 50) {
      $('#navbar')
        .addClass('bg-black/90')
        .removeClass('bg-black/50 border-white/5');
    } else {
      $('#navbar')
        .removeClass('bg-black/90')
        .addClass('bg-black/50 border-white/5');
    }
  });

  // 4. Hero Animations on Load
  const tl = gsap.timeline();
  tl.to('.hero-anim', {
    y: 0,
    opacity: 1,
    duration: 1.2,
    stagger: 0.2,
    ease: 'power4.out',
    delay: 0.5,
  });

  // Fade in Hero Card
  gsap.from('#hero-card', {
    scale: 0.9,
    opacity: 0,
    duration: 1.5,
    ease: 'power3.out',
    delay: 0.2,
  });

  // 5. Parallax Effect for Gallery Columns
  if (window.innerWidth > 768) {
    $('.parallax-col').each(function () {
      const speed = $(this).data('speed');
      gsap.to($(this), {
        yPercent: -20 * speed,
        ease: 'none',
        scrollTrigger: {
          trigger: '#gallery',
          start: 'top bottom',
          end: 'bottom top',
          scrub: true,
        },
      });
    });
  }

  // 6. Text Reveal on Scroll
  gsap.from('.text-reveal-trigger', {
    scrollTrigger: {
      trigger: '#about',
      start: 'top 80%',
    },
    y: 50,
    opacity: 0,
    duration: 1,
    ease: 'power3.out',
  });

  // 7. Image reveal animations
  $('.portfolio-item img').each(function () {
    gsap.from(this, {
      scrollTrigger: {
        trigger: this,
        start: 'top 90%',
      },
      scale: 1.2,
      opacity: 0,
      duration: 1.5,
      ease: 'power2.out',
    });
  });
});

Final Output:

free-photography-website-template-html-tailwind-and-gsap-2026.gif

Conclusion:

And that's it! You now have a sleek, responsive, and animated photography homepage. By using Tailwind CSS, you saved hours of styling time, and GSAP added that premium "agency" feel that clients love.

Important Note: All images used in this template are copyright by owner CodeWithFaraz. Please take explicit permission before using them for commercial purposes.

Want the Full Experience?

This free guide covers the Homepage. If you want to take your business to the next level with a complete website including:

  • 18 Fully Designed Pages (About, Portfolios, Services, Book, Blog, Contact, 404, etc.)
  • Advanced animations and page transitions
  • Fully responsive design across all devices

Check out the full version here: codewithfaraz.com/shop

That’s a wrap!

I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Components

Please allow ads on our site🥺