如何制作两个字母交换的动画?

How do I animate two letters swapping?

我正在尝试制作一个网站,将鼠标悬停在由两个字母换位组成的拼写错误上可以更正它,如下所示:

var swap = document.querySelector('.swap');

swap.addEventListener('mouseover', swapIn);
swap.addEventListener('mouseout', swapOut);

function swapIn(e) {
  e.target.parentNode.firstChild.classList.toggle('shifted-right');
  e.target.parentNode.lastChild.classList.toggle('shifted-left');
}

function swapOut(e) {
  e.target.parentNode.firstChild.classList.toggle('shifted-right');
  e.target.parentNode.lastChild.classList.toggle('shifted-left');
}
body {
  font-size: 24px;
}

.swap {
  display: inline;
}

span {
    -webkit-transition: all 0.3s linear;
    -moz-transition: all 0.3s linear;
    -o-transition: all 0.3s linear;
    transition: all 0.3s linear;
}

.shifted-right {
  margin-left: 20px;
  color: blue;
}

.shifted-left {
  margin-left: -25px;
  color: red;
}
E<div class="swap" id="swap"><span class="left-swap" id="ls">q</span><span class="right-swap" id="rs">c</span></div>uis me vivit fortunatior?

但是,如您所见,字母不能很好地交换,此外,我不想为每个不同的字母宽度计算精确的边距。

执行此操作的更好方法是什么?

可以通过使用 offsetLeft 属性.

计算它们与其父项的相对位置来切换同一个单词中的两个字母

相互减去值并使用Math.abs保持整数为正数。这个数字就是两个字母之间的distance。一个字母必须向左移动整个距离,而另一个向右移动相同的距离才能切换位置。用距离设置一个 CSS 变量,这样我们就可以将计算传递给 CSS.

在 CSS 中,我们可以使用 :hover 伪选择器设置悬停样式,并使用 CSS 变量进行适当的转换。不要将鼠标悬停在一个字母上,而是将鼠标悬停在整个单词上。

代替margin,使用transform;这 属性 不会扰乱布局,只会对目标元素进行任何操作。

const word = document.querySelector('.word');
const [e, a] = word.querySelectorAll('.letter');
const distance = Math.abs(e.offsetLeft - a.offsetLeft);
word.style.setProperty('--distance', `${distance}px`);
.word {
  display: inline-block;
  padding: 15px;
  position: relative;
  font-size: 32px;
  background-color: #f7f7f7;
  border: 1px dashed #d0d0d0;
  border-radius: 3px;
  cursor: help;
}

.word .letter {
  display: inline-block;
  color: red;
  transition: color 500ms ease-in-out, transform 500ms ease-in-out;
}

.word:hover .letter {
  color: green;
}

.word:hover .letter:first-of-type {
  transform: translate(var(--distance), 0);
}

.word:hover .letter:last-of-type {
  transform: translate(calc(var(--distance) * -1), 0);
}
<span class="word">
  App<span class="letter">e</span>r<span class="letter">a</span>nt
</span>