Search code examples
htmlcssbuttoncss-transitionswidth

How to prevent text moving when transitioning sibling element's width


I'm developing a website that will have a "learn more" button that's split in two, one part says "learn more" and the other says "+". When the mouse hovers over it the "learn more" part disappears and the "+" grows to take up the entire space of the button, and I'm doing that by animating the width of both halves of the button with css. The problem is that the text is moving/wrapping as the width of the element reduces. Here's a gif of how the button is working right now: learn more button

I want to find a way for the text to stay in place and just disappear behind the "+" element without wrapping as the mouse hovers over the button. I've searched online and I've tried playing around with the word-wrap and position properties and I've also tried putting the button texts in inside a paragraph but I haven't been able to make it work. I have a feeling it's something simple but I just haven't been able to work it out. Or if there's a simpler way to create a button with this functionality I would also love to know. Here's my code:

.button-container {
  height: 4vw;
  width: 19vw;
  display: flex;
  align-items: center;
  padding: 0;
  border: none;
  cursor: pointer;
}

.button {
  height: 4vw;
  align-content: center;
  font-family: "Comfortaa", cursive;
  transition-duration: 0.6s;
  transition-property: width;
  transition-timing-function: ease-in-out;
}

.button-label {
  width: 15vw;
  background: #07BEB8;
  color: #FFF;
  font-size: 1.3vw;
  overflow: hidden;
}

.button-symbol {
  width: 4vw;
  background: #3DCCC7;
  color: #FFF;
  border-left: solid #FFF;
  font-size: 1.6vw;
  font-weight: bold;
}

.button-container:hover .button-label {
  width: 0;
}

.button-container:hover .button-symbol {
  width: 19vw;
}

```
<button class="button-container">
            <div class="button button-label">Learn More</div>
            <div class="button button-symbol">+</div>
        </button>


Solution

  • Since grid-template-columns is animatable, one option is to use grid instead and animate the grid column sizes. By this, you can set overflow:hidden on the label and prevent changing its width so that the text won't move.

    .button-container {
      height: 4vw;
      width: 19vw;
      align-items: center;
      padding: 0;
      border: none;
      cursor: pointer;
      display: grid;
      grid-template-columns: 15vw 4vw;
      transition-duration: 0.6s;
      transition-property: grid-template-columns;
      transition-timing-function: ease-in-out;
    }
    
    .button {
      height: 4vw;
      align-content: center;
      font-family: "Comfortaa", cursive;
    }
    
    .button-label {
      overflow: hidden;
      width: 15vw;
      background: #07BEB8;
      color: #FFF;
      font-size: 1.3vw;
      overflow: hidden;
    }
    
    .button-symbol {
      width: 100%;
      background: #3DCCC7;
      color: #FFF;
      border-left: solid #FFF;
      font-size: 1.6vw;
      font-weight: bold;
    }
    
    .button-container:hover {
      grid-template-columns: 0vw 19vw;
    }
    <button class="button-container">
        <div class="button button-label">Learn More</div>
        <div class="button button-symbol">+</div>
    </button>

    Also, though off topic, you might notice there was originally a flicker when the window width is changed. This is because the animated property is based on window width. This can be solve by using a wrapper and define the 19vw width on it instead, so that the animated width can be based on percentage value that the proportion won't change when resizing the window.

    .wrapper {
      width: 19vw;
    }
    
    .button-container {
      height: 4vw;
      align-items: center;
      padding: 0;
      border: none;
      cursor: pointer;
      display: grid;
      width: 100%;
      grid-template-columns: calc(15/19 * 100%) calc(4/19 * 100%);
      transition: grid-template-columns 0.6s ease-in-out
    }
    
    .button {
      height: 4vw;
      align-content: center;
      font-family: "Comfortaa", cursive;
    }
    
    .button-label {
      overflow: hidden;
      width: 15vw;
      background: #07BEB8;
      color: #FFF;
      font-size: 1.3vw;
      overflow: hidden;
    }
    
    .button-symbol {
      width: 100%;
      background: #3DCCC7;
      color: #FFF;
      border-left: solid #FFF;
      font-size: 1.6vw;
      font-weight: bold;
    }
    
    .button-container:hover {
      grid-template-columns: 0vw 19vw;
    }
    <div class="wrapper">
      <button class="button-container">
          <div class="button button-label">Learn More</div>
          <div class="button button-symbol">+</div>
      </button>
    </div>