Search code examples
jqueryeventtriggermouseenterclip-path

jQuery mouseenter/leave event triggers do not always behave the same


Using gsap, clip-path and overlays, what I am aiming to do is hover over the word ".image-title" and an image will appear giving the effect that the text only being framed by the image will change to have white outline. (Easier to show than explain..)

Codepen here: https://codepen.io/tallulahh/pen/bGgOpXd

let container, text, img, title;

function showImage(id){
  switch(id){
    case 'portfolio':
    title = $(".portfolio .image-title");
    container = $(".portfolio .overlay-container")
    text = $(".portfolio .image-overlay");
    img = $(".portfolio img");
    break;
    case 'arcade':
    title = $(".arcade .image-title");
    container = $(".arcade .overlay-container")
    text = $(".arcade .image-overlay");
    img = $(".arcade img");
    break;
    case 'sailing':
    title = $(".sailing .image-title");
    container = $(".sailing .overlay-container")
    text = $(".sailing .image-overlay");
    img = $(".sailing img");
    break;
    default:
  }
  var t = new gsap.timeline({duration:0.2});
  t.to(title, {
    zIndex: 0,
  });
  t.to( container, {
    opacity: 1,
    zIndex: 200,
  });
  t.to(img, {
    opacity: 1,
    zIndex: 200,
  });
  t.to(text, {
    opacity:0.5,
    zIndex: 300,
  }, "-0.3");
}

function reverseImage(id){
  switch(id){
    case 'portfolio':
    title = $(".portfolio .image-title");
    container = $(".portfolio .overlay-container")
    text = $(".portfolio .image-overlay");
    img = $(".portfolio img");
    break;
    case 'arcade':
    title = $(".arcade .image-title");
    container = $(".arcade .overlay-container")
    text = $(".arcade .image-overlay");
    img = $(".arcade img");
    break;
    case 'sailing':
    title = $(".sailing .image-title");
    container = $(".sailing .overlay-container")
    text = $(".sailing .image-overlay");
    img = $(".sailing img");
    break;
    default:
  }

var t = new gsap.timeline();
t.to(container, {
  opacity: 0,
  zIndex: 0,
  duration:1
});
t.to(img, {
  opacity: 0,
  zIndex: 0,
  duration:1
});
  t.to(title, {
    zIndex: 200,
    duration: 0
  });
  t.to(text, {
    opacity: 0,
    zIndex: 0,
    duration:0
  });
}


$(".projects .content ul li p.image-title").on("mouseenter", function(){
  showImage($(this)[0].id);
});
$(".projects .content ul li p.image-title").on("mouseleave", function(){

  reverseImage($(this)[0].id);
});
body {
 box-sizing:border-box;
}
.main section{
  width: 75%;
  min-height: 100vh;
  margin: 0 auto;
  position: relative;
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
}
.project-list {
   display: flex;
   flex-direction: column;
   align-items: center;
   justify-content: center;
   width: 100vw;
   left: 50%;
   transform: translateX(-75%);
   position: relative;
   text-align: center;
   margin-top: 100px;
 }

.project-list li {
  font-size: 100px;
  list-style-type: none;
  width: 100vw;
  border-top: 2px solid black;
  font-weight: bold;
}

.project-list li p {
  margin-top: 50px;
}

.project-list:last-child {
  border-bottom: 2px solid black;
}

.image {
  width: 100%;
  height: 300px;
  position: relative;
  margin: 0 auto;
  display: flex;
  flex-direction: row;
  justify-content:center;
  align-items:center;
}

.image img {
  width: 500px;
  height: 300px;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
  overflow: hidden;
  z-index: 0;
}
.image-title {
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke-width: 3px;
  -webkit-text-stroke-color: black;
  cursor: pointer;
  font-family: "Raleway"!important;
  font-size: 110px;
  font-weight: bold;
  width: 100%;
  display: flex;
  position: absolute;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 200;
  cursor: pointer;
  height:100px;
}
.overlay-container {
  width: 500px;
  height: 300px;
  display: flex;
  position: relative;
  justify-content: center;
  align-items: center;
  overflow:hidden;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
  opacity: 0;
  z-index: 0;
  pointer-events: none;
}

.image-overlay{
  -webkit-text-fill-color: transparent;
  -webkit-text-stroke-width: 1px;
  -webkit-text-stroke-color: white;
  font-family: "Raleway"!important;
  font-size: 110px;
  font-weight: bold;
  height: 100%;
  width: 200%;
  display: flex;
  position: absolute;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  opacity: 0;
  z-index: 0;
  pointer-events: none;
}
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@100;800&display=swap" rel="stylesheet">
<div class="main">
<section class="projects">
        <div class="heading">
          <h1>Projects</h1>
        </div>
        <div class="content">
          <p>To see some of my featured projects, click on the following titles to launch.. </p>
          <ul class="project-list">
            <li>
              <div class="portfolio">
                <div class="image" id="portfolio-img">
                  <p class="image-title" id="portfolio">Portfolio</p>
                  <div class="overlay-container">
                    <p class="image-overlay">Portfolio</p>
                    <img src="https://upload.wikimedia.org/wikipedia/commons/5/59/500_x_300_Ramosmania_rodriguesii_%28Rubiaceae%29.jpg" alt="portfolio">
                  </div>
                </div>
              </div>
            </li>
            <li>
              <div class="arcade">
                <div class="image" id="arcade-img">
                  <p class="image-title" id="arcade">Arcade</p>
                  <div class="overlay-container">
                    <p class="image-overlay">Arcade</p>
                    <img src="https://upload.wikimedia.org/wikipedia/commons/5/59/500_x_300_Ramosmania_rodriguesii_%28Rubiaceae%29.jpg" alt="arcade">
                  </div>
                </div>
              </div>
            </li>
            <li>
              <div class="sailing">
                <div class="image" id="sailing-img">
                  <p class="image-title" id="sailing">Sailing Barcelona</p>
                  <div class="overlay-container">
                    <p class="image-overlay">Sailing Barcelona</p>
                    <img src="https://upload.wikimedia.org/wikipedia/commons/5/59/500_x_300_Ramosmania_rodriguesii_%28Rubiaceae%29.jpg" alt="sailing">
                  </div>
                </div>
              </div>
            </li>
          </ul>
        </div>
      </section>
  </div>

<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.5.1/gsap.min.js"></script>

My problem is the jQuery event triggers and that sometimes the white outline appears on top of the image and sometimes it does not. It is tricky because i want the image and white outline to appear ontop of the original text, but the original text needs to be listening for the event triggers and be clickable whilst the image is visible.

Could someone explain why sometimes the white ouline text appears and why sometimes it doesn't and how I could fix this?


Solution

  • Someone kindly offered me this answer in GreenSock forum:

    " There are a few things going on here that will compete with each other at times, producing unexpected results. Here are a few tips I can point out to help reduce the chances of unexpected results.

    1. When at all possible, rely on the DOM hierarchy to handle stacking order. While it is reasonable to modify z-indexes to change stacking order, many times it's just not necessary. Removing that from the equation greatly reduces the potential for the unexpected. In my fork, I flipped the order of the .image-overlay and the img within .overlay-container.
    2. If you expect Javascript to change a CSS property on an element, use Javascript to set its initial presentation value too; don't use CSS to define initial properties (like opacity and visible) that will be tweened. You can see I went through the CSS and ripped out all things z-index, opacity, visible, etc. This will also help with graceful degradation in the event that Javascript doesn't execute.
    3. When possible, create a timeline once (not over and over with each event trigger).
    4. When possible, don't use two timelines to control the same elements. In your example, a timeline is created for each of the in/out states. But we can create one timeline and play it forward/reverse as needed for the hover event.

    Lastly, by dynamically creating variable names for timelines, we can create them (once) and address them repeatedly without the need to keep recreating them and without the bulky logic of switch statements. "

    Corrected code pen here: https://greensock.com/forums/topic/27944-gsap-timeline-sometimes-works-correct-and-sometimes-does-not/?tab=comments#comment-137674