CSS: How to make active tab show the same gradient slice as parent container (no separate gradient)?

1 week ago 13
ARTICLE AD BOX

I have a layout where tabs are visually part of the same gradient container.

The block consists of:

.purchase-tabs — 3 buttons at the top

.purchase-panel — the main panel below

The panel () has a gradient background and looks correct..purchase-panel

What I want

When a tab is active, I want it to look like it’s cut out from the same parent gradient, i.e. like a window into the gradient behind it.

Meaning:

the gradient must NOT restart inside the tab button

the active tab background should be the same exact gradient slice that exists at that position in the main container

visually it should look like one continuous gradient across the whole block

So the active tab should match the panel gradient seamlessly. BAD RESULT -> GOOD RESULT

"use client"; import { useState } from "react"; type TabType = "gamepass" | "giftcard" | "superpass"; export default function PurchaseMethods() { const [activeTab, setActiveTab] = useState<TabType>("gamepass"); return ( <section className={`purchase-methods-section purchase-methods--${activeTab}`}> <div className="purchase-methods-container"> {/* 3 tabs */} <div className="purchase-tabs"> <button className={`purchase-tab ${activeTab === "gamepass" ? "active" : ""}`} onClick={() => setActiveTab("gamepass")} type="button" > 1 </button> <button className={`purchase-tab ${activeTab === "giftcard" ? "active" : ""}`} onClick={() => setActiveTab("giftcard")} type="button" > 2 </button> <button className={`purchase-tab ${activeTab === "superpass" ? "active" : ""}`} onClick={() => setActiveTab("superpass")} type="button" > 3 </button> </div> {/* content 1/2/3 */} <div className="purchase-panel"> <div className="purchase-content">Content {activeTab}</div> </div> </div> </section> ); } /* Purchase Methods Section */ .purchase-methods-section { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 1376px; margin: 0 auto; } .purchase-methods-header { margin: 0; font-size: 24px; font-weight: 500; color: var(--text); } .purchase-methods-container { width: 100%; position: relative; filter: drop-shadow(8px 4px 30px rgba(138, 126, 87, 0.12)); } /* Tabs */ .purchase-tabs { display: grid; grid-template-columns: 1fr 1fr 1fr; width: 100%; isolation: isolate; border-radius: 20px 20px 0 0; overflow: hidden; } .purchase-tab { display: flex; justify-content: center; align-items: center; padding: 16px 10px; height: 55px; background: transparent; border: none; font-size: 20px; font-weight: 500; color: var(--accent); cursor: pointer; position: relative; transition: all 0.3s ease; } .purchase-tab:first-child { border-radius: 20px 0 0 0; } .purchase-tab:last-child { border-radius: 0 20px 0 0; } .purchase-tab.active { background: linear-gradient(95deg, #E4D497 0%, #DECA83 29.91%, #C8B46F 74.42%, #AF9A5C 99.71%); color: #fff; border-radius: 20px 20px 0 0; } .purchase-tab.active:first-child { border-radius: 20px 20px 0 0; } .purchase-tab.active:last-child { border-radius: 20px 20px 0 0; } /* Content Panel */ .purchase-panel { width: 100%; background: linear-gradient(95deg, #E4D497 0%, #DECA83 29.91%, #C8B46F 74.42%, #AF9A5C 99.71%); border-radius: 0 0 20px 20px; padding: 40px 32px 32px; } .purchase-content { max-width: 913px; margin: 0 auto; display: flex; flex-direction: column; gap: 30px; } .purchase-title { margin: 0; text-align: center; font-size: 28px; font-weight: 500; color: #fff; }
Read Entire Article