Oblique Hero Hero Block - Let's templates
Unlock every premium block and template with All-Access from $20 / 3 months, cancel anytime. Get All-Access
All blocks
Free Hero

Oblique Hero

A hero block extracted from the Oblique template, available in Tailwind CSS and Bootstrap.

0 3
Oblique Hero preview
oblique.html
<!DOCTYPE html>
<html lang="en">
<head>
  <script>
    window.FontAwesomeConfig = { autoReplaceSvg: 'nest' };
  </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Oblique Hero | Tailwind CSS UI Block</title>
  <meta name="description" content="A hero block extracted from the Oblique template, available in Tailwind CSS and Bootstrap.">
  <meta name="keywords" content="Oblique, Tailwind CSS template, HTML website template, fashion ecommerce, clothing store template, minimal online boutique, capsule wardrobe shop, responsive store design">
  <meta name="author" content="Let's templates">
  <link rel="canonical" href="">

  <meta property="og:type" content="product">
  <meta property="og:site_name" content="Let's templates">
  <meta property="og:locale" content="en_US">
  <meta property="og:url" content="">
  <meta property="og:title" content="Oblique | Tailwind CSS Fashion Ecommerce Template">
  <meta property="og:description" content="A minimal Tailwind CSS fashion ecommerce template for independent clothing labels, capsule wardrobes, and slow-fashion boutiques that sell online.">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="Oblique template preview">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:url" content="">
  <meta name="twitter:title" content="Oblique | Tailwind CSS Fashion Ecommerce Template">
  <meta name="twitter:description" content="A minimal Tailwind CSS fashion ecommerce template for independent clothing labels, capsule wardrobes, and slow-fashion boutiques that sell online.">
  <meta name="twitter:image" content="">
  <meta name="twitter:image:alt" content="Oblique template preview">
  <script src="https://cdn.tailwindcss.com/3.4.17"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Courier+Prime:wght@700&amp;family=Inter:wght@400;500;600&amp;family=Inter+Tight:wght@400;500;600&amp;display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            paper: '#faf9f6',
            ink: '#141414',
            stone: '#6d6b66',
            line: '#e5e2db',
            sand: '#efece6'
          },
          fontFamily: {
            sans: ['Inter', 'Helvetica Neue', 'Arial', 'sans-serif'],
            display: ['"Inter Tight"', 'Helvetica Neue', 'Arial', 'sans-serif'],
            mono: ['"Courier Prime"', 'Courier New', 'monospace']
          }
        }
      }
    };
  </script>
  <style>
    @view-transition {
      navigation: auto;
    }
    ::view-transition-old(root) {
      animation: 180ms ease-out both page-fade-out;
    }
    ::view-transition-new(root) {
      animation: 220ms ease-in both page-fade-in;
    }
    @keyframes page-fade-out {
      to { opacity: 0; }
    }
    @keyframes page-fade-in {
      from { opacity: 0; }
    }
    @media (prefers-reduced-motion: reduce) {
      ::view-transition-old(root),
      ::view-transition-new(root) {
        animation: none;
      }
    }
    .reveal-ready [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .6s ease, transform .6s ease; transition-delay: var(--reveal-delay, 0ms); }
    .reveal-ready [data-reveal].is-visible { opacity: 1; transform: none; }
  </style>
</head>
<body class="overflow-x-hidden bg-paper font-sans text-ink antialiased">
<!-- block:start hero -->
    <section id="hero" class="mx-auto max-w-[1600px] px-5 pb-16 pt-2 sm:px-8 lg:px-10 lg:pb-24">
      <div class="grid gap-8 md:grid-cols-2 md:gap-10">
        <figure class="aspect-[4/5] overflow-hidden bg-sand md:aspect-auto md:h-[640px] lg:h-[780px]">
          <img src="https://images.unsplash.com/photo-1571513722275-4b41940f54b8?auto=format&fit=crop&w=1200&q=80" alt="Model in a cream tailored suit standing against a pale studio wall" class="h-full w-full object-cover object-top">
        </figure>
        <div class="flex flex-col justify-end" data-reveal>
          <h1 class="font-display text-[42px] font-medium uppercase leading-[0.98] tracking-[-0.02em] sm:text-6xl lg:text-[64px] xl:text-[68px]">Quiet lines.<br>Honest motion.</h1>
          <p class="mt-6 max-w-[400px] text-[15px] leading-[1.35] text-ink/85">Pared-back pieces for days that move at your own pace. Precise cuts, considered shapes, fabrics you want to touch. Nothing extra — just what earns its place.</p>
          <a href="new-collection.html" class="mt-6 inline-flex h-14 w-full max-w-[420px] items-center justify-center bg-ink text-base text-white transition-colors hover:bg-black/80">See the collection</a>
        </div>
      </div>
    </section>
    <!-- block:end hero -->
<script>
    document.querySelectorAll("[data-menu-toggle]").forEach((button) => {
      const menu = document.getElementById(button.getAttribute("aria-controls"));
      if (!menu) return;
      button.addEventListener("click", () => {
        const open = button.getAttribute("aria-expanded") === "true";
        button.setAttribute("aria-expanded", String(!open));
        button.setAttribute("aria-label", open ? "Open menu" : "Close menu");
        menu.classList.toggle("hidden", open);
      });
    });

    (() => {
      const counters = document.querySelectorAll("[data-cart-count]");
      const read = () => {
        try { return localStorage.getItem("oblique-bag-count"); } catch (error) { return null; }
      };
      const write = (value) => {
        try { localStorage.setItem("oblique-bag-count", String(value)); } catch (error) {}
      };
      const stored = Number(read());
      let count = read() === null || Number.isNaN(stored) ? Number(counters[0]?.textContent || 0) : stored;
      const render = () => counters.forEach((counter) => { counter.textContent = count; });
      render();
      document.querySelectorAll("[data-add-to-cart]").forEach((button) => {
        const label = button.textContent;
        button.addEventListener("click", () => {
          const qtyInput = button.dataset.qtySource ? document.querySelector(button.dataset.qtySource) : null;
          count += qtyInput ? Math.max(1, Number(qtyInput.value) || 1) : 1;
          write(count);
          render();
          button.textContent = "Added to bag";
          setTimeout(() => { button.textContent = label; }, 1400);
        });
      });
    })();

    document.querySelectorAll("[data-filter-group]").forEach((group) => {
      const items = group.closest("section").querySelectorAll("[data-filter-items] [data-category]");
      const activeClasses = ["bg-ink", "text-white"];
      group.addEventListener("click", (event) => {
        const button = event.target.closest("[data-filter]");
        if (!button) return;
        const filter = button.dataset.filter;
        group.querySelectorAll("[data-filter]").forEach((chip) => {
          const active = chip === button;
          chip.setAttribute("aria-pressed", String(active));
          activeClasses.forEach((cls) => chip.classList.toggle(cls, active));
        });
        items.forEach((item) => {
          item.hidden = !(filter === "all" || item.dataset.category.split(" ").includes(filter));
        });
      });
    });

    document.querySelectorAll("[data-carousel]").forEach((carousel) => {
      const track = carousel.querySelector("[data-carousel-track]");
      const slides = [...track.children];
      const dots = carousel.querySelector("[data-carousel-dots]");
      let index = 0;
      const perView = () => Math.max(1, Math.round(track.clientWidth / slides[0].clientWidth));
      const maxIndex = () => Math.max(0, slides.length - perView());
      const render = () => {
        track.style.transform = `translateX(-${index * slides[0].clientWidth}px)`;
        dots?.querySelectorAll("button").forEach((dot, i) => dot.setAttribute("aria-current", String(i === index)));
      };
      const go = (next) => { const max = maxIndex(); index = next > max ? 0 : next < 0 ? max : next; render(); };
      const buildDots = () => {
        if (!dots) return;
        dots.innerHTML = "";
        for (let i = 0; i <= maxIndex(); i++) {
          const dot = document.createElement("button");
          dot.type = "button";
          dot.className = "h-2 w-6 bg-current opacity-20 transition-opacity aria-[current=true]:opacity-100";
          dot.setAttribute("aria-label", `Go to review ${i + 1}`);
          dot.addEventListener("click", () => go(i));
          dots.append(dot);
        }
      };
      carousel.querySelector("[data-carousel-prev]")?.addEventListener("click", () => go(index - 1));
      carousel.querySelector("[data-carousel-next]")?.addEventListener("click", () => go(index + 1));
      addEventListener("resize", () => { buildDots(); go(Math.min(index, maxIndex())); });
      buildDots();
      render();
    });

    document.querySelectorAll("[data-form-message]").forEach((form) => {
      form.addEventListener("submit", (event) => {
        event.preventDefault();
        const status = form.querySelector("[data-form-status]");
        if (status) status.textContent = form.dataset.formMessage;
        form.reset();
      });
    });

    (() => {
      const items = document.querySelectorAll("[data-reveal]");
      const skip = navigator.webdriver || /HeadlessChrome/.test(navigator.userAgent) || !("IntersectionObserver" in window) || matchMedia("(prefers-reduced-motion: reduce)").matches;
      if (!items.length || skip) return;
      document.documentElement.classList.add("reveal-ready");
      const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (!entry.isIntersecting) return;
          entry.target.classList.add("is-visible");
          observer.unobserve(entry.target);
        });
      }, { rootMargin: "0px 0px -10% 0px" });
      items.forEach((item) => observer.observe(item));
    })();
  </script>
</body>
</html>

From this template

Oblique screenshot

E-commerce

Oblique

Unlimited access to all products

Unlock the entire library of premium templates and blocks. Renews automatically, cancel anytime.

$20 / 3 months or $60 / year
Get Unlimited Access