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 secondaryCtaHref = heroData?.secondaryCtaHref || '/products';
|
||||||
const slogan = siteConfig.slogan || COMPANY_INFO.slogan;
|
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 (
|
return (
|
||||||
<section
|
<section
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
@@ -208,9 +216,7 @@ function HeroSection({ heroData }: {
|
|||||||
{/* 品牌口号 Badge:画布上的品牌红信号(深底走 brand-light 保证对比度;hero 不重复渲染 Logo,避免与导航栏重复) */}
|
{/* 品牌口号 Badge:画布上的品牌红信号(深底走 brand-light 保证对比度;hero 不重复渲染 Logo,避免与导航栏重复) */}
|
||||||
{slogan && (
|
{slogan && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
{...rise(20, 0.03)}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.35, delay: 0.03, ease: EASE_OUT }}
|
|
||||||
className="mb-6"
|
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'}`}>
|
<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 切换) */}
|
{/* 主标题:大胆、直接(深底白色 / 浅底墨色,随 HERO_VARIANT 切换) */}
|
||||||
<motion.h1
|
<motion.h1
|
||||||
initial={{ opacity: 0, y: 40 }}
|
{...rise(40, 0.06, 0.45)}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.45, delay: 0.06, ease: EASE_OUT }}
|
|
||||||
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'}`}
|
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}
|
{heading}
|
||||||
@@ -232,9 +236,7 @@ function HeroSection({ heroData }: {
|
|||||||
{/* 主张:紧随声明之后,回答「凭什么信你」(声明先行,数据下沉至成果带) */}
|
{/* 主张:紧随声明之后,回答「凭什么信你」(声明先行,数据下沉至成果带) */}
|
||||||
{subheading && (
|
{subheading && (
|
||||||
<motion.p
|
<motion.p
|
||||||
initial={{ opacity: 0, y: 30 }}
|
{...rise(30, 0.16)}
|
||||||
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'}`}
|
className={`text-lg sm:text-xl max-w-2xl leading-relaxed mb-10 ${dark ? 'text-white/70' : 'text-text-secondary'}`}
|
||||||
>
|
>
|
||||||
{subheading}
|
{subheading}
|
||||||
@@ -243,9 +245,7 @@ function HeroSection({ heroData }: {
|
|||||||
|
|
||||||
{/* CTA 按钮组 */}
|
{/* CTA 按钮组 */}
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 30 }}
|
{...rise(30, 0.24)}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
transition={{ duration: 0.35, delay: 0.24, ease: EASE_OUT }}
|
|
||||||
className="flex flex-col sm:flex-row sm:items-center gap-4 sm:gap-6"
|
className="flex flex-col sm:flex-row sm:items-center gap-4 sm:gap-6"
|
||||||
>
|
>
|
||||||
<CTAButton href={ctaHref} dataTestId="hero-primary-cta">{ctaLabel}</CTAButton>
|
<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">
|
<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">
|
<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="flex items-center justify-center gap-3 mb-8">
|
||||||
<div className="w-10 h-px bg-brand/40" />
|
<div className="w-10 h-px bg-brand/40" />
|
||||||
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
|
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
|
||||||
|
|||||||
Reference in New Issue
Block a user