How to make text translate in / grow in width during hover transition

Viewed 76

I have a .card which shows an arrow by default. When a user hovers over this .card, I want the "learn more" text to slide in from the right and move the arrow with it.

I have tried to put .card__footer to width: 0; then try give it width on hover, but, because the text is transitioning in, sometimes it appears on two lines, then once transition is over, becomes one line.

How can I get this effect to work on hover besides using width? Or what is the correct way to implement it? My current approach:

.cards {
  background: lightblue;
  padding: 60px 0;
}

.container {
  max-width: 720px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 auto;
}

.card {
  background-color: white;
  padding: 30px;
  cursor: pointer;
  transition: all 0.5s ease;
  width: 250px;
}
.card:hover {
  box-shadow: 0px 20px 25px 0px rgba(0, 0, 0, 0.1);
}
.card:hover .card__arrow {
  transform: translateX(5px);
}
.card:hover .card__label {
  display: inline-block;
  visibility: visible;
  margin-right: 6px;
  opacity: 1;
}
.card__header {
  margin-bottom: 30px;
}
.card__footer {
  display: flex;
  justify-content: flex-start;
  align-items: center;
}
.card__label {
  margin-right: 10px;
}
@media (hover: hover) {
  .card__label {
    margin: 0;
    transition: opacity 0.5s;
    visibility: hidden;
    opacity: 0;
    display: none;
  }
}
<div class="cards">
  <div class="container">

    <div class="card">
      <div class="card__header">
        header
      </div>
      <div class="card__footer">
        <span class="card__label">Learn more</span>
        <img class="card__arrow" src="https://i.imgur.com/onjXVGW.png" alt="arrow" />
      </div>
    </div>

    <div class="card">
      <div class="card__header">
        header 2
      </div>
      <div class="card__footer">
        <span class="card__label">Learn more</span>
        <img class="card__arrow" src="https://i.imgur.com/onjXVGW.png" alt="arrow" />
      </div>
    </div>


  </div>
</div>

What I'm after:

  • .footer__arrow shows by default left side (as it does in the demo)
  • .footer__label is hidden by default
  • On .card hover, I want the .footer__label to slide in, pushing the arrow image with it (so that it shows "learn more" and then the arrow on hover.
  • Currently my .footer__label just appears, whereas I want the label to slide in slowly and give it the effect that my arrow is being pushed alongside it.
2 Answers

Using transform: You can introduce one wrapper for label and arrow. And then transform it to the right on hover. And on footer make overflow hidden:

:root {
  --arrow-icon-size: 1.5rem;
}

.cards {
  background: lightblue;
  padding: 25px 0;
}

.container {
  max-width: 720px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 auto;
}

.card {
  background-color: white;
  padding: 20px;
  cursor: pointer;
  transition: all 0.5s ease;
  width: 250px;
  border-radius: 1rem;
  margin: 0 0.5rem;
}

.card__header {
  margin-bottom: 30px;
}

.card__footer {
  overflow: hidden;
}

.card__slide {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  width: fit-content;
  
  transform: translateX(calc(-100% + var(--arrow-icon-size)));
  transition: transform 1s ease-out;
}

.card__label {
  display: inline-block;
  margin-right: 0.3rem;
}

.card__arrow {
  color: #FF7C81;
  font-size: var(--arrow-icon-size);
}

@media (hover: hover) {
  .card:hover {
    box-shadow: 0px 20px 25px 0px rgba(0, 0, 0, 0.4);
  }
  .card:hover .card__slide {
    transform: translateX(0);
  }
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet" />

<div class="cards">
  <div class="container">

    <div class="card">
      <div class="card__header">header 1</div>
      <div class="card__footer">
        <div class="card__slide">
          <span class="card__label">Learn more</span>
          <i class="card__arrow fas fa-chevron-circle-right"></i>
        </div>
      </div>
    </div>

    <div class="card">
      <div class="card__header">header 2</div>
      <div class="card__footer">
        <div class="card__slide">
          <span class="card__label">Learn more</span>
          <i class="card__arrow fas fa-chevron-circle-right"></i>
        </div>
      </div>
    </div>

  </div>
</div>


Using width: You can achieve reveal effect by transitioning label width:

    .cards {
      background: lightblue;
      padding: 20px 0;
    }

    .container {
      max-width: 720px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin: 0 auto;
    }

    .card {
      background-color: white;
      padding: 20px;
      cursor: pointer;
      transition: all 0.5s ease;
      width: 250px;
      border-radius: 1rem;
      margin: 0.5rem;
    }

    .card__header {
      margin-bottom: 30px;
    }

    .card__footer {
      display: flex;
      justify-content: flex-start;
      align-items: center;
      width: fit-content;
    }

    .card__label {
      display: inline-block;
      width: 0;
      overflow: hidden;
      white-space: nowrap;

      transition: width 1s ease-out;
      margin-right: 0.3rem;
    }

    .card__arrow {
      color: #FF7C81;
      font-size: 1.5rem;
    }

    @media (hover: hover) {
      .card:hover {
        box-shadow: 0px 20px 25px 0px rgba(0, 0, 0, 0.4);
      }

      .card:hover .card__label {
        width: 100%;
      }
    }
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet" />

<div class="cards">
  <div class="container">

    <div class="card">
      <div class="card__header">header 1</div>
      <div class="card__footer">
          <span class="card__label">Learn more</span>
          <i class="card__arrow fas fa-chevron-circle-right"></i>
      </div>
    </div>

    <div class="card">
      <div class="card__header">header 2</div>
      <div class="card__footer">
          <span class="card__label">Learn more</span>
          <i class="card__arrow fas fa-chevron-circle-right"></i>
      </div>
    </div>

  </div>
</div>


Imgur doesn't allow some origins in its CORS policy. So for the demo, I've used fontawesome chevron-circle-right as arrows.

Not totally sure this is what you are asking for but it will hopefully give you some insight into what you are attempting.

.cards {
  background: lightblue;
  padding: 60px 0;
}

.container {
  max-width: 720px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 0 auto;
}

.card {
  background-color: white;
  padding: 30px;
  cursor: pointer;
  transition: all 0.5s ease;
  width: 250px;
}

.card:hover {
  box-shadow: 0px 20px 25px 0px rgba(0, 0, 0, 0.1);
}

.card:hover .card__arrow {
  transform: translateX(5px);
}

.card:hover .card__label {
  display: inline-block;
  visibility: visible;
  margin-right: 6px;
}

.card__header {
  margin-bottom: 30px;
}

.card__footer {
  display: flex;
  justify-content: flex-start;
  align-items: center;
}

.card .card__footer::after {
  content: "";
  transform: translateX(60px);
  transition: transform .5s linear;
    

}

.card:hover .card__footer::after {
  transform: translateX(36px);
  content: "Learn More";
  transition:transform .5s linear;

}

.card__label {
  margin-right: 10px;
}

@media (hover: hover) {
  .card__label {
    margin: 0;
    transition: opacity 0.5s;
    visibility: hidden;
    opacity: 0;
    display: none;
  }
}
<div class="cards">
  <div class="container">

    <div class="card">
      <div class="card__header">
        header
      </div>
      <div class="card__footer">
        <img class="card__arrow" src="https://i.imgur.com/onjXVGW.png" alt="arrow" />
      </div>
    </div>

    <div class="card">
      <div class="card__header">
        header 2
      </div>
      <div class="card__footer">
        <img class="card__arrow" src="https://i.imgur.com/onjXVGW.png" alt="arrow" />
      </div>
    </div>


  </div>
</div>

Related