skip to Main Content

I am working on a button hover effect where the individual characters flip up when you hover. This works almost perfectly but somehow it removes the space in between the words so the button now says ‘Thisisatext’ instead of ‘This is a text’, I tried so many things but can’t seem to find the right solution:

Demo:

https://codepen.io/pixelarchitect/pen/mdQXjgx

SCSS:

.btn-text {
transform: translateY(var(--y)) translateZ(0);
transition: transform 0.3s ease;

  div {
  display: flex;
  overflow: hidden;
  text-shadow: 0 1rem 0 white;

    span {
    display: block;
    backface-visibility: hidden;
    transition: transform 0.25s ease;
    transform: translateY(var(--m)) translateZ(0);

      @for $i from 1 through 12 {
        &:nth-child(#{$i}) {
          transition-delay: $i * 0.05s;
        }
      }
    }
  }

  &:hover {
    span {
      --m: calc(1rem * -1);
    }
  }

}

JS:

document.querySelectorAll('.btn-text').forEach(button => {
const words = button.textContent.trim().split(' ');
button.innerHTML = '<div>' + words.map(word => '<span>' + word.split('').join('</span><span>') + '</span>').join(' ') + '</div>';
});

2

Answers


  1. You are breaking the sentence in single words to then put them back together wrapped in spans; that’s when you lose the spaces since span is an inline container.

    This is what you get:

    <button class="btn btn-primary btn-text"><div><span>This</span><span>is</span><span>a</span><span>text</span></div></button>
    

    Add a space in HTML code when you put the words together. &nbsp;

    document.querySelectorAll('.btn-text').forEach(button => {
      const words = button.textContent.trim().split(' ');
      button.innerHTML = '<div>' + words.map(word => '<span>' + word.split('').join('</span><span>') + '</span>').join('&nbsp;') + '</div>';
    });
    
    Login or Signup to reply.
  2. Add white-space: pre to your <span />‘s

    ...
    span {
          white-space: pre;
          ...
    

    preserve whitespace in the JS:

    document.querySelectorAll(".btn-text").forEach((button) => {
      const words = button.textContent.trim().split("");
      button.innerHTML =
        "<div>" + words.map((word) => `<span>${word}</span>`).join("") + "</div>";
    });
    

    working demo (codepen)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search