构建拆分文本动画

关于如何构建拆分字母和文字动画的基本概览。

在这篇博文中,我想与大家分享解决拆分文本动画的思路, 尽可能减少、可访问并且可跨浏览器进行的网络互动。 试用演示版

<ph type="x-smartling-placeholder">
</ph> 演示

如果你更喜欢视频,可以参阅此博文的 YouTube 版本:

概览

拆分文本动画效果非常棒。我们只是触及了 但这确实为构建和扩展动画奠定了基础 。目标是以渐进方式呈现动画效果。这些文字应 其动画效果基于其构建拆分文本的动作效果 会显得过于奢华并且可能会造成破坏,因此我们只会操纵 HTML,或 如果用户可以接受动画,请应用动画样式。

下面概要介绍了工作流程和结果:

  1. 准备减少动作条件 用于 CSS 和 JS 的变量
  2. Prepare 拆分文本实用程序: JavaScript。
  3. 编排页面上的条件和实用程序 加载。
  4. 编写 CSS 过渡和动画 代表字母和单词(Rad 部分!)。

下面是我们将要获取的条件结果的预览:

Chrome 开发者工具的屏幕截图,其中“元素”面板已打开,“减少动态”设置为“减少”h1 显示为未拆分的
用户更喜欢减少动态:文字清晰可辨 / 不拆分

如果用户更喜欢减少动作,我们就不考虑 HTML 文档, 动画。如果可以,我们直接把它切成片状。这里有 在 JavaScript 按字母拆分文本后预览 HTML。

Chrome 开发者工具的屏幕截图,其中“元素”面板已打开,“减少动态”设置为“减少”h1 显示为未拆分的
用户没有问题;拆分成多个 <span> 的文本元素

正在准备动作条件

将在 CSS 中使用方便的 @media (prefers-reduced-motion: reduce) 媒体查询, 此项目中的 JavaScript。此媒体查询是我们 决定是否拆分文本。CSS 媒体查询将用于 转换和动画,而 JavaScript 媒体查询将用于 避免 HTML 操作。

准备 CSS 条件

我使用 PostCSS 启用了媒体查询级别 5 的语法, 将媒体查询布尔值转换为变量:

@custom-media --motionOK (prefers-reduced-motion: no-preference);

准备 JS 条件

在 JavaScript 中,浏览器提供了一种检查媒体查询的方式,我曾使用过 解构 从媒体查询检查中提取布尔值结果并重命名:

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

然后,我可以测试 motionOK,并仅在用户未更改文档时才更改文档 请求减少移动

if (motionOK) {
  // document split manipulations
}

我可以使用 PostCSS 从 启用 @nest 语法, 嵌套草稿 1。这样,我便可以 存储有关动画的所有逻辑及其样式要求 父级和子级

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

有了 PostCSS 自定义属性和 JavaScript 布尔值,我们就可以 有条件地升级效应。接下来我们将进入下一部分 分解用于将字符串转换为元素的 JavaScript。

拆分文本

无法使用 CSS 或 JS 为文字、文字、行等分别添加动画效果。 为了实现这个效果,我们需要箱子。如果我们想为每个字母添加动画效果,那么 每个字母都需要是一个元素。如果我们想为每个单词添加动画效果, 单词需要是一个元素。

  1. 创建用于将字符串拆分为元素的 JavaScript 实用函数
  2. 编排这些实用程序的使用

拆分字母实用函数

最有趣的示例是先调用一个函数,该函数接受一个字符串, 数组中的字母。

export const byLetter = text =>
  [...text].map(span)

通过 分散 语法对这一快速任务有很大帮助。

拆分词实用函数

与拆分字母类似,此函数接受一个字符串并返回每个单词 放在数组中。

export const byWord = text =>
  text.split(' ').map(span)

通过 split() 方法指定按哪些字符进行切片。 我传递了一个空格,表示字词之间存在拆分。

使框实用功能

效果需要分别用方框标出每个字母,我们在这些功能中可以看到, map() 使用 span() 函数进行调用。以下是 span() 函数。

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

请务必注意,名为 --index 的自定义属性是使用 数组位置。为字母动画添加方框是很好的做法, 在 CSS 中使用索引看似微不足道,影响巨大。 这一巨大影响中最显著的一点是 令人难以置信。 我们可以使用 --index 作为交错动画的偏移方式 看看。

“公用事业”总结

splitting.js 模块完成:

const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)

  return node
}

export const byLetter = text =>
  [...text].map(span)

export const byWord = text =>
  text.split(' ').map(span)

接下来是导入并使用 byLetter()byWord() 函数。

拆分编排

拆分实用程序可供使用后,将这一切整合在一起意味着:

  1. 查找要拆分的元素
  2. 拆分文本并使用 HTML 替换文本

然后,CSS 会接管工作,并为元素 / 方框添加动画效果。

查找元素

我选择使用属性和值来存储 以及拆分文本的方法。我喜欢将这些声明式选项 嵌入到 HTML 中。JavaScript 中的属性 split-by 用于查找 元素,并为字母或字词创建方框。属性 在 CSS 中使用 letter-animationword-animation 来定位元素 子项以及 apply 转换和动画。

以下 HTML 示例展示了这两个属性:

<h1 split-by="letter" letter-animation="breath">animated letters</h1>
<h1 split-by="word" word-animation="trampoline">hover the words</h1>

从 JavaScript 中查找元素

我使用 CSS 选择器语法了解属性存在性,以收集 元素:

const splitTargets = document.querySelectorAll('[split-by]')

从 CSS 中查找元素

我还使用了 CSS 中的属性存在状态选择器,以显示所有字母动画 基本样式相同稍后,我们会使用属性值 样式来实现某种效果。

letter-animation {
  @media (--motionOK) {
    /* animation styles */
  }
}

就地拆分文本

对于我们在 JavaScript 中找到的每个拆分目标,我们都会将其文本拆分成 并将每个字符串映射到 <span>。我们可以 然后将元素文本替换为我们创建的框:

splitTargets.forEach(node => {
  const type = node.getAttribute('split-by')
  let nodes = null

  if (type === 'letter') {
    nodes = byLetter(node.innerText)
  }
  else if (type === 'word') {
    nodes = byWord(node.innerText)
  }

  if (nodes) {
    node.firstChild.replaceWith(...nodes)
  }
})

编排总结

已完成 index.js

import {byLetter, byWord} from './splitting.js'

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

if (motionOK) {
  const splitTargets = document.querySelectorAll('[split-by]')

  splitTargets.forEach(node => {
    const type = node.getAttribute('split-by')
    let nodes = null

    if (type === 'letter')
      nodes = byLetter(node.innerText)
    else if (type === 'word')
      nodes = byWord(node.innerText)

    if (nodes)
      node.firstChild.replaceWith(...nodes)
  })
}

可以用以下英语读取 JavaScript:

  1. 导入一些辅助实用函数。
  2. 检查此用户是否可以使用动作,如果不什么也不做。
  3. 针对要拆分的每个元素。
    1. 请根据具体的拆分方式来拆分它们。
    2. 将文本替换为元素。

拆分动画和过渡

上述拆分文档操作已经解锁了许多 并支持通过 CSS 或 JavaScript 添加各种动画和效果这里有一些链接 ,以便激发您的拆分潜力。

是时候展示您可以运用这项技能了!我会分享 4 个由 CSS 驱动的动画 过渡效果。🤓

拆分字母

作为拆分字母效果的基础,我发现以下 CSS 非常有帮助。我将所有过渡和动画效果置于动作媒体查询之后, 然后为每个新的子字母 span 指定一个显示属性和样式, 如何处理空格:

[letter-animation] > span {
  display: inline-block;
  white-space: break-spaces;
}

空格样式很重要,以使这些 span 只是一个空格, 布局引擎不会收起。接下来是有状态的有趣玩意儿。

转换拆分字母示例

此示例使用了针对拆分文本效果的 CSS 过渡。通过过渡, 我选择了三种状态:否 鼠标悬停在句子中,鼠标悬停在字母上。

当用户将鼠标悬停在句子(也就是容器)上时, 就像被用户推远一样。然后,当用户将鼠标悬停在 我要把它带上去

@media (--motionOK) {
  [letter-animation="hover"] {
    &:hover > span {
      transform: scale(.75);
    }

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:hover {
        transform: scale(1.25);
      }
    }
  }
}

动画拆分字母示例

此示例使用预定义的 @keyframe 动画为每个视频添加无限动画 字母,并利用内嵌自定义属性索引来创建交错的 效果。

@media (--motionOK) {
  [letter-animation="breath"] > span {
    animation:
      breath 1200ms ease
      calc(var(--index) * 100 * 1ms)
      infinite alternate;
  }
}

@keyframes breath {
  from {
    animation-timing-function: ease-out;
  }
  to {
    transform: translateY(-5px) scale(1.25);
    text-shadow: 0 0 25px var(--glow-color);
    animation-timing-function: ease-in-out;
  }
}

拆分字词

在这些示例中,我使用了 Flexbox 作为一种容器 将 ch 单位作为健康的间隔长度。

word-animation {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1ch;
}
<ph type="x-smartling-placeholder">
</ph>
显示字词间间隔的 Flexbox 开发者工具

过渡拆分字词示例

在这个过渡示例中,我将再次使用悬停操作。由于该效果最初会隐藏 确保仅应用互动和样式 。

@media (hover) {
  [word-animation="hover"] {
    overflow: hidden;
    overflow: clip;

    & > span {
      transition: transform .3s ease;
      cursor: pointer;

      &:not(:hover) {
        transform: translateY(50%);
      }
    }
  }
}

动画拆分字词示例

在此动画示例中,我再次使用 CSS @keyframes 来创建一个交错的 为普通文本段落添加无限动画。

[word-animation="trampoline"] > span {
  display: inline-block;
  transform: translateY(100%);
  animation:
    trampoline 3s ease
    calc(var(--index) * 150 * 1ms)
    infinite alternate;
}

@keyframes trampoline {
  0% {
    transform: translateY(100%);
    animation-timing-function: ease-out;
  }
  50% {
    transform: translateY(0);
    animation-timing-function: ease-in;
  }
}

总结

现在你知道我怎么做到的了,你会怎么做?!🙂

让我们一起采用多样化的方法,学习所有在 Web 上构建应用的方法。 创建一个 Codepen 或托管自己的演示,将它发到 Twitter 微博中,然后我会将其添加到 下方的“社区混剪作品”部分。

来源

更多演示和灵感

社区混剪作品