1

I'm trying to make this news item component interface for a blog. Each item shows a story image and some of the text of the article. Rolling over the news item should "scrunch up" the image and reveal more of the text of the article. I can't see why my animation does not hold when you rollover the item, and then it resets completely before performing the "unscrunching."

There are keyframe animations that attach and detach to the item:

@keyframes scrunch {
  from {
    height: 50%;
  }

  to {
    height: 10%;
  }
}

@keyframes unscrunch {
  from {
    height: 10%;
  }

  to {
    height: 50%;
  }
}

.scrunch {
  animation: scrunch 1s;
}

.unscrunch {
  animation: unscrunch 1s;
}

Then I'm just adding and removing those classes from the news item class list:

const scrunchyBox = document.getElementById('scrunchyBox1');
const children = scrunchyBox.childNodes;
console.dir(children);
const scrunchyBoxHead = children[1];

scrunchyBox.addEventListener('pointerover', (event) => {
  scrunchyBoxHead.classList.remove('unscrunch');
  scrunchyBoxHead.classList.add('scrunch');
});

scrunchyBox.addEventListener('pointerout', (event) => {
  scrunchyBoxHead.classList.remove('scrunch'); 
  scrunchyBoxHead.classList.add('unscrunch');
});

Seems basic, but whatever I'm doing looks gross. Everything I've done is over at my Codepen.

russellmania
  • 640
  • 2
  • 8
  • 21

2 Answers2

1
  1. You can retain the animation in its final state using animation-fill-mode: forwards; as described in answer to this question: Maintaining the final state at end of a CSS3 animation

  2. It will still look janky if you remove pointer from the box mid-animation. I am not sure why you don't want to simply use CSS :hover with transition.

Maksym Shcherban
  • 742
  • 4
  • 13
  • To your #2, `:hover` would only allow me to change attributes within the element that the hover was applied to, not to elements inside that element. Is that not right? To that end, using an event listener to listen for mouseover events is doing the same thing while allowing me to change elements inside the moused over element. – russellmania Nov 05 '21 at 16:03
  • 1
    No, that is not right, you can use CSS nesting for that like this: `element:hover nestedElement { ... }` – Maksym Shcherban Nov 05 '21 at 16:34
1

You can use the transition property with the :hover pseudo-class. This will be the same that you have tryed to do with javascript.

To achieve this, just add few lines to your css file.

/* new block */
.scrunchyBox:hover .sectionHead {
  height: 10%;
}
/* new block */
.scrunchyBox:hover .datedot {
  transform: scale(0.45) translate(60px, -72px);
}

.scrunchyBox > .sectionHead {
  transition: all 0.5s ease-in-out; /* new line */
}
.datedot {
  transition: all 0.5s ease-in-out; /* new line */
}

body {
  background-color: #ccc;
  font-size: 18px;
}

.scrunchyBox {
  color: #333;
  position: relative;
  background-color: #fff;
  width: 400px;
  height: 400px;
  margin: 0 auto;
  padding: 20px;
  overflow: hidden;
  filter: drop-shadow(4px 4px 4px #333);
}

/* new block */
.scrunchyBox:hover .sectionHead {
  height: 10%;
}
/* new block */
.scrunchyBox:hover .datedot {
  transform: scale(0.45) translate(60px, -72px);
}

.scrunchyBox > .sectionHead {
  width: 400px;
  height: 250px;
  background-color: #3ab7f4;
  padding: 0;
  margin: 0 auto;
  transition: all 0.5s ease-in-out; /* new line */
}

.datedot {
  position: absolute;
  top: 30px;
  right: 30px;
  background-color: rgba(0, 0, 0, 0.3);
  padding: 12px;
  border-radius: 60px;
  width: 60px;
  height: 60px;
  transition: all 0.5s ease-in-out; /* new line */
}

.datedot > span {
  font-family: 'Trebuchet MS', sans-serif;
  color: rgba(255, 255, 255, 1);
  text-align: center;
  display: block;
  margin: 0;
}

.datedot > span.day {
  font-size: 2.2em;
  font-weight: bold;
  line-height: 0.8em;
  padding: 0;
}

.datedot > span.month {
  font-size: 1.3em;
  font-weight: normal;
  text-transform: uppercase;
  padding: 0;
}

.scrunchyBox > h2 {
  font-family: 'Trebuchet MS', sans-serif;
  font-size: 1.2em;
  line-height: 1em;
  padding: 0;
}

.scrunchyBox > p {
  font-family: 'Georgia', serif;
  font-size: 1.4em;
}
<div id="scrunchyBox1" class="scrunchyBox">
  <div class="sectionHead">
    <div class="datedot">
      <span class="day">30</span>
      <span class="month">Oct</span>
    </div>
  </div>
  <h2>A Headline for the Scrunchy Box</h2>
  <p>
    This is some text that would normally be some text that the reader would want to see more of. It gets cut off here by other elements, but then other elements "scrunch" in order to reveal more of the text for a preview.
  </p>
</div>
Anton
  • 8,058
  • 1
  • 9
  • 27
  • Yes. I am aware of this method. Can it be used to cause multiple sub-elements to transform. I had not done it yet in my Codepen example, but I was eventually planning on multiple effects, for instance the date dot shrinking. – russellmania Nov 06 '21 at 17:16
  • 1
    Yes, you can to use `multiple sub-elements to transform`, when you set `:hover` to the parent element. Snippet updated. – Anton Nov 06 '21 at 17:45
  • Excellent! Thanks for the enlightenment. Using :hover is potentially more powerful than I thought. – russellmania Nov 06 '21 at 19:53
  • 1
    Just a note for anyone who comes along later: you can also use `transform-origin` to get elements to scale to a particular point. In my case, `transform-origin: top right;` ensures that the date in the circle shrinks up and right. – russellmania Nov 06 '21 at 20:05