tab切换动画,背景图向内收缩效果,主图片缓慢展开效果(含自适应)
先看效果:https://live.csdn.net/v/492602
tab切换,切换动画,页面自适应
PS:
- 这里的sm、md是在global.css中自定义的断点
- 代码中样式用的是tailwindcss,颜色可能有自定义的,可根据自身需要自行修改
- sm以下是移动端,tab在下面,左右点击切换
- 动画的速度和透明度变化可根据自己的要求更改具体数据
"use client";import { useState } from "react";const Test = () => {const [activeTab, setActiveTab] = useState(0);const [animationKey, setAnimationKey] = useState(0);const tabs = [{id: 0,title: "tab1",content: "tab1 alt",bgImage: "/bg-img/bg1.jpeg",mainImage: "/image/liuyifei11.jpeg",},{id: 1,title: "tab2",content: "tab2 alt",bgImage: "/bg-img/bg2.jpeg",mainImage: "/image/liuyifei12.jpeg",},{id: 2,title: "tab3",content: "tab3 alt",bgImage: "/bg-img/bg3.jpeg",mainImage: "/image/liuyifei13.jpeg",},{id: 3,title: "tab4",content: "tab4 alt",bgImage: "/bg-img/bg4.jpeg",mainImage: "/image/liuyifei14.jpeg",},];const nextTab = () => {setActiveTab((prev) => (prev + 1) % tabs.length);setAnimationKey((prev) => prev + 1);};const prevTab = () => {setActiveTab((prev) => (prev - 1 + tabs.length) % tabs.length);setAnimationKey((prev) => prev + 1);};const handleTabClick = (tabId: number) => {if (tabId === activeTab) return;setActiveTab(tabId);setAnimationKey((prev) => prev + 1);};const currentTab = tabs[activeTab];return (<div className="w-full">{/* Desktop: Tab栏导航 (sm以上) - 放在上面 */}<div className="hidden max-w-[1440px] mx-auto sm:flex md:px-[100px] lg:px-0 justify-center items-center"><div className="flex w-full">{tabs.map((tab) => (<buttonkey={tab.id}onClick={() => handleTabClick(tab.id)}className={`flex-1 px-4 py-2 text-sm leading-4 md:text-base md:leading-[18px] transition-all duration-300 border-b-2 ${activeTab === tab.id? "border-green-300 text-green-300 font-semibold": "border-transparent text-gray-400"}`}>{tab.title}</button>))}</div></div><div className="relative py-10 px-5 sm:px-10 md:px-[105px] md:pt-[50px] md:pb-[61px] overflow-hidden">{/* Background Image - 根据当前tab动态切换 */}<divkey={`bg-${animationKey}`}className="absolute inset-0 w-full h-full bg-cover bg-center bg-no-repeat animate-background-shrink"style={{backgroundImage: `url('${currentTab.bgImage}')`,}}/>{/* Content Area */}<div className="relative max-w-[1440px] mx-auto h-full rounded-[12px] sm:rounded-[20px] md:rounded-[30px] bg-gradient-to-br from-gray-50/33 to-white/33">{/* Overlay Content */}<div className="relative z-10 w-full h-full flex items-center justify-center p-1.5 sm:p-[15px]">{/* Main Image Container - 根据当前tab动态切换 */}<div className="relative w-full h-full flex items-center justify-center rounded-[8px] sm:rounded-[15px] md:rounded-[20px] overflow-hidden"><imgkey={`img-${animationKey}`}src={currentTab.mainImage}alt={`${currentTab.title} Content`}className="w-full h-full object-cover drop-shadow-xl animate-image-expand rounded-[8px] sm:rounded-[15px] md:rounded-[20px]"/></div></div></div>{/* Mobile: 左右按钮导航 (sm以下) - 放在下面 */}<div className="flex items-center justify-between sm:hidden mt-8">{/* 左侧导航按钮 */}<buttononClick={prevTab}className="w-[50px] h-[50px] rounded-full backdrop-blur-md border-2 border-gray-200 shadow-xl hover:bg-white/30 transition-all duration-300 flex items-center justify-center group"><imgsrc="icons/arrow-left.svg"className="h-5 w-5 text-gray-200 drop-shadow-lg group-hover:scale-110 transition-transform duration-200"/></button>{/* 中央标题 */}<div className="text-center"><h3 className="text-sm leading-[16px] font-semibold text-white drop-shadow-lg tracking-wide">{currentTab.title}</h3></div>{/* 右侧导航按钮 */}<buttononClick={nextTab}className="w-[50px] h-[50px] rounded-full backdrop-blur-md border-2 border-gray-200 shadow-xl hover:bg-white/30 transition-all duration-300 flex items-center justify-center group"><imgsrc="icons/arrow-right.svg"className="h-5 w-5 text-gray-200 drop-shadow-lg group-hover:scale-110 transition-transform duration-200"/></button></div></div></div>);
};export default Test;
css样式
@theme {--breakpoint-sm: 810px;--breakpoint-md: 1200px;
}/* Tab切换动画 */
@keyframes backgroundShrink {0% {transform: scale(1.05);}100% {transform: scale(1);}
}@keyframes imageExpand {0% {opacity: 0;transform: scale(0.97);}100% {opacity: 1;transform: scale(1);}
}.animate-background-shrink {animation: backgroundShrink 0.2s ease-out forwards;transform: scale(1.05);
}.animate-image-expand {animation: imageExpand 0.3s ease-out forwards;opacity: 0;transform: scale(0.97);
}