I am trying to make a website where hovering over a misspelling consisting of transposition of two letters corrects it, like so:
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 id="swap"><span id="ls">q</span><span id="rs">c</span></div>uis me vivit fortunatior?
However, as you can see, the letters don't swap well, and besides, I don't want to calculate the precise margins for each different letter width.
What's a better approach to doing this?
CodePudding user response:
Switching two letters in the same word can be done by calculating their relative position to their parent with the offsetLeft property.
Subtract the values from each other and use Math.abs to keep the integer a positive number. This number is the distance between the two letters. One letter has to go the entire distance to the left and the other the same distance to the right to switch positions. Set the a CSS Variable with the distance so we can pass the calculation to CSS.
In CSS we can use the :hover psuedo selector to set styles on hover and use the CSS Variable to make the proper transition. And instead of target a hover on a letter, target the hover on the entire word.
Instead of margin, use transform; this property does not mess with the layout and will only any manipulate the element that is targeted.
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 >
App<span >e</span>r<span >a</span>nt
</span>
