mcpField
M
masked-reveal

masked-reveal

github.com/mengto设计与 UI7.1k1.7k 次安装3 天前更新
代码仓库

关于 masked-reveal

用于使用 GSAP 和 ScrollTrigger 制作错落式遮罩文字显现的设计技能。内容涵盖初始化、无障碍、清理和动效默认值,适用于短标题与章节引言。

主要功能

  1. 01滚动时让文字逐词显现
  2. 02使用 GSAP 设置逐词错落
  3. 03保留空格与无障碍文本
  4. 04支持减少动态效果及路由清理

适用场景

  1. 01为落地页标题添加动效
  2. 02滚动时显现章节引言

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mengto/skills --skill masked-reveal

安装后在 Claude Code 中输入/masked-reveal确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

demo/
index.html
PROMPT.md
source.json

详细介绍

遮罩揭示

适用场景

  • 标题或简短文本块需要在滚动时呈现高级感的揭示效果。
  • 文字应从不可见的遮罩中逐词上升,并按顺序错开出现。
  • 项目已使用 GSAP,或需要基于 ScrollTrigger 的动效。

动效默认值

  • 触发时机:文本顶部到达视口的 82% 处时开始。
  • 时长:0.7s 到 0.9s。
  • 错开间隔:每个词 0.025s 到 0.045s。
  • 偏移:从 yPercent: 110 到 0。
  • 缓动:power3.out 或 expo.out。
  • 重播:默认只揭示一次。

HTML

<h1 class="masked-reveal" data-masked-reveal>
  Design systems that feel alive from the first scroll.
</h1>

CSS 遮罩

.masked-reveal {
  visibility: visible;
}

html.js .masked-reveal[data-masked-reveal] {
  visibility: hidden;
}

html.js .masked-reveal.is-split {
  visibility: visible;
}

.masked-reveal .word-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
}

.masked-reveal .word {
  display: inline-block;
  transform: translateY(110%);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  html.js .masked-reveal[data-masked-reveal] {
    visibility: visible;
  }

  .masked-reveal .word {
    transform: none;
  }
}

GSAP ScrollTrigger

这个辅助函数无需使用付费的 SplitText 插件,并能保留空格。

document.documentElement.classList.add("js");
gsap.registerPlugin(ScrollTrigger);

function escapeHTML(value) {
  return value
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

function splitMaskedReveal(element) {
  if (element.dataset.maskedRevealReady === "true") return;

  const text = element.textContent.trim();
  element.setAttribute("aria-label", text);
  element.innerHTML = text
    .split(/(\s+)/)
    .map((part) => {
      if (!part.trim()) return part;
      return `<span class="word-mask" aria-hidden="true"><span class="word">${escapeHTML(part)}</span></span>`;
    })
    .join("");
  element.dataset.maskedRevealReady = "true";
  element.classList.add("is-split");
}

function initMaskedReveals(selector = "[data-masked-reveal]") {
  if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;

  document.querySelectorAll(selector).forEach((element) => {
    splitMaskedReveal(element);
    const words = element.querySelectorAll(".word");

    gsap.set(element, { autoAlpha: 1 });
    gsap.fromTo(
      words,
      { yPercent: 110 },
      {
        yPercent: 0,
        duration: 0.8,
        ease: "power3.out",
        stagger: 0.035,
        scrollTrigger: {
          trigger: element,
          start: "top 82%",
          once: true,
        },
      }
    );
  });
}

initMaskedReveals();

React 清理模式

useLayoutEffect(() => {
  const ctx = gsap.context(() => {
    initMaskedReveals("[data-masked-reveal]");
  }, rootRef);

  return () => ctx.revert();
}, []);

风格规则

  • 用于简短标题、标签和章节引言;避免用于长段落。
  • 保持垂直偏移干净利落。除非风格明确要求,否则不要搭配模糊效果。
  • 按词而非按字母错开,营造更沉静的编辑风格。
  • 如果换行至关重要,请在字体加载完成后再初始化。
  • 图片延迟加载或布局发生偏移后,使用 ScrollTrigger.refresh()。
  • 不要拆分包含链接、按钮或有意义的行内标记的文本。

快速检查

  • GSAP 初始化前文本处于隐藏状态,随后通过 autoAlpha: 1 显示。
  • 屏幕阅读器通过 aria-label 获取完整的原始文本。
  • 单词之间的空格得以保留。
  • 使用减少动态效果设置的用户会看到静态文本。
  • 在 SPA 路由中清理 ScrollTrigger。

评论

支持 Markdown