fix(a11y): guard Hero entrance animations with reduced-motion; tone down founder card shadow
- Hero 入场 motion.* 未守卫 reduced-motion,与 ScrollReveal 范式不一致 - 新增 rise() 守卫:reduce 时传空 initial/animate,元素静态可见 - 创始团队引言卡 shadow-xl 降级 shadow-sm + 品牌红 hairline 边框
This commit is contained in:
@@ -175,6 +175,14 @@ function HeroSection({ heroData }: {
|
||||
const secondaryCtaHref = heroData?.secondaryCtaHref || '/products';
|
||||
const slogan = siteConfig.slogan || COMPANY_INFO.slogan;
|
||||
|
||||
// reduced-motion 守卫:与 ScrollReveal 同范式——reduce 时传空 initial/animate,
|
||||
// 元素直接以自然(可见)状态渲染,零位移/淡入;默认(非 reduce,含首帧 null)正常动画。
|
||||
const rise = (y: number, delay: number, duration = 0.35) => ({
|
||||
initial: reduceMotion ? {} : { opacity: 0, y },
|
||||
animate: reduceMotion ? {} : { opacity: 1, y: 0 },
|
||||
transition: { duration: reduceMotion ? 0 : duration, delay: reduceMotion ? 0 : delay, ease: EASE_OUT },
|
||||
});
|
||||
|
||||
return (
|
||||
<section
|
||||
ref={containerRef}
|
||||
@@ -208,9 +216,7 @@ function HeroSection({ heroData }: {
|
||||
{/* 品牌口号 Badge:画布上的品牌红信号(深底走 brand-light 保证对比度;hero 不重复渲染 Logo,避免与导航栏重复) */}
|
||||
{slogan && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.35, delay: 0.03, ease: EASE_OUT }}
|
||||
{...rise(20, 0.03)}
|
||||
className="mb-6"
|
||||
>
|
||||
<span className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium border ${dark ? 'bg-brand/10 text-brand-light border-brand/30' : 'bg-brand/5 text-brand border-brand/15'}`}>
|
||||
@@ -221,9 +227,7 @@ function HeroSection({ heroData }: {
|
||||
|
||||
{/* 主标题:大胆、直接(深底白色 / 浅底墨色,随 HERO_VARIANT 切换) */}
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.45, delay: 0.06, ease: EASE_OUT }}
|
||||
{...rise(40, 0.06, 0.45)}
|
||||
className={`text-4xl sm:text-5xl md:text-6xl lg:text-6xl 2xl:text-7xl font-bold leading-[1.05] tracking-tight mb-7 sm:mb-8 ${dark ? 'text-white' : 'text-ink'}`}
|
||||
>
|
||||
{heading}
|
||||
@@ -231,21 +235,17 @@ function HeroSection({ heroData }: {
|
||||
|
||||
{/* 主张:紧随声明之后,回答「凭什么信你」(声明先行,数据下沉至成果带) */}
|
||||
{subheading && (
|
||||
<motion.p
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.35, delay: 0.16, ease: EASE_OUT }}
|
||||
className={`text-lg sm:text-xl max-w-2xl leading-relaxed mb-10 ${dark ? 'text-white/70' : 'text-text-secondary'}`}
|
||||
>
|
||||
<motion.p
|
||||
{...rise(30, 0.16)}
|
||||
className={`text-lg sm:text-xl max-w-2xl leading-relaxed mb-10 ${dark ? 'text-white/70' : 'text-text-secondary'}`}
|
||||
>
|
||||
{subheading}
|
||||
</motion.p>
|
||||
)}
|
||||
|
||||
{/* CTA 按钮组 */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.35, delay: 0.24, ease: EASE_OUT }}
|
||||
{...rise(30, 0.24)}
|
||||
className="flex flex-col sm:flex-row sm:items-center gap-4 sm:gap-6"
|
||||
>
|
||||
<CTAButton href={ctaHref} dataTestId="hero-primary-cta">{ctaLabel}</CTAButton>
|
||||
@@ -637,7 +637,7 @@ function FounderQuoteSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
|
||||
/>
|
||||
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
|
||||
<ScrollReveal className="max-w-4xl mx-auto text-center">
|
||||
<div className="bg-bg-primary/95 rounded-2xl p-8 sm:p-10 md:p-12 max-w-3xl mx-auto shadow-xl">
|
||||
<div className="bg-bg-primary/95 rounded-2xl p-8 sm:p-10 md:p-12 max-w-3xl mx-auto shadow-sm border border-brand/10">
|
||||
<div className="flex items-center justify-center gap-3 mb-8">
|
||||
<div className="w-10 h-px bg-brand/40" />
|
||||
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
|
||||
|
||||
Reference in New Issue
Block a user