2

I have a circle bar animation that should trigger when in view. The effect works on every Browser but in Google Chrome and I can't understand why.

Here an example: https://career.foundationbox.studio

I made a Pen to isolate the problem: https://codepen.io/davide-fanchin/pen/xxydBNY

I suspect is something related to the Javascript code: Any suggestion is welcome.

document.addEventListener('DOMContentLoaded', () => {
  const circleProgressBar = document.querySelector('.circle-progress-value');
  const circleProgressNumber = document.querySelector('.circle-progress-number');
  const checkmarkContainer = document.querySelector('.checkmark-container');

  const countUp = (start, end, element, duration) => {
    let current = start;
    const stepTime = Math.abs(Math.floor(duration / (end - start)));
    const timer = setInterval(() => {
      if (current <= end) {
        element.textContent = current++;
      } else {
        clearInterval(timer);
      }
    }, stepTime);
  };

  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        circleProgressBar.style.transitionDuration = `2000ms`;
        circleProgressBar.style.strokeDashoffset = '0';
        countUp(0, 50, circleProgressNumber, 2000);
        setTimeout(() => {
          checkmarkContainer.style.opacity = '1';
        }, 2000);
      } else {
        circleProgressBar.style.strokeDashoffset = '283';
        circleProgressNumber.textContent = '0';
        checkmarkContainer.style.opacity = '0';
      }
    });
  }, {
    threshold: 0.5
  });

  observer.observe(circleProgressBar);
});
.circle-progress-container {
  position: relative;
  display: inline-block;
  width: 100%;
  padding-bottom: 100%;
  overflow: visible;
}

.bar-container {
  width: 400px;
}

.circle-progress {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.circle-progress-bg,
.circle-progress-value {
  stroke-linecap: round;
}

.circle-progress-bg {
  stroke: lightgray;
}

.circle-progress-value {
  stroke: url(#circle-gradient-%id%);
  stroke-dasharray: 283;
  stroke-dashoffset: 283;
  transition: stroke-dashoffset 2s;
}

.circle-progress-text {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: bold;
  text-align: center;
  /* Added to center the text */
}

.circle-progress-number-container {
  display: flex;
  align-items: baseline;
}

.circle-progress-number {
  transition: 2s;
}

.circle-progress-label {
  font-size: 12px;
  font-weight: normal;
  margin-top: -10px;
  /* Adjust the margin to separate the count up number and the word "Projects" */
}

.checkmark-container {
  position: absolute;
  top: -2px;
  /* Adjusted to lower the checkmark icon and circle */
  left: 50%;
  transform: translateX(-50%);
  opacity: 0;
  transition: opacity 0.5s, transform 0.5s;
}

.checkmark-circle {
  position: relative;
  width: calc(%id=iconSize%px + 5px);
  height: calc(%id=iconSize%px + 5px);
  background-color: white;
  border-radius: 50%;
  box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
}

.checkmark {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  stroke: deepskyblue;
  stroke-linecap: round;
}

@media screen and (-webkit-min-device-pixel-ratio:0) {
  .circle-progress-value {
    stroke: deepskyblue;
    stroke-dasharray: 283;
    stroke-dashoffset: 283;
    -webkit-transition: stroke-dashoffset 2s;
  }
}
<div class="bar-container">
  <div class="circle-progress-container">
    <svg class="circle-progress" viewBox="0 0 100 100">
    <defs>
      <linearGradient id="circle-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:red"/>
        <stop offset="100%" style="stop-color:blue"/>
      </linearGradient>
    </defs>
    <circle class="circle-progress-bg" cx="50" cy="50" r="45" stroke-width="1" fill="none" />
    <circle class="circle-progress-value" cx="50" cy="50" r="45" stroke-width="1" fill="none" />
  </svg>
    <div class="circle-progress-text">
      <div class="circle-progress-number-container" style="font-size: 40px;">
        <span class="circle-progress-number">50</span><span>+</span>
      </div>
      <div class="circle-progress-label" style="font-size: 14px;">Projects</div>
    </div>
    <div class="checkmark-container">
      <div class="checkmark-circle">
        <svg class="checkmark" width="16px" height="16px" viewBox="0 0 20 20">
        <polyline points="6,10 9,13 14,8" stroke-width="2" fill="none" />
      </svg>
      </div>
    </div>
  </div>
</div>
isherwood
  • 58,414
  • 16
  • 114
  • 157
Holaloro
  • 23
  • 2
  • Same problem on Edge BTW (as is to be expected as it's same as Chrome under the skin). The problem is that the circle never gets its intersecting state set as true. The observer is attached to it thoug- if you console.log inside the function you'll see that initially it is there in the entries but set to false. – A Haworth Apr 27 '23 at 08:06

1 Answers1

0

The problem seems to be that Chrome (and Edge) does not see intersections of the SVG circle.

This snippet puts the observer onto the whole containing element and that seems to be OK.

<!document html>
<html>

<head>
  <style>
    .circle-progress-container {
      position: relative;
      display: inline-block;
      width: 100%;
      padding-bottom: 100%;
      overflow: visible;
    }
    
    .bar-container {
      width: 400px;
    }
    
    .circle-progress {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      transform: rotate(-90deg);
    }
    
    .circle-progress-bg,
    .circle-progress-value {
      stroke-linecap: round;
    }
    
    .circle-progress-bg {
      stroke: lightgray;
    }
    
    .circle-progress-value {
      stroke: url(#circle-gradient-%id%);
      stroke-dasharray: 283;
      stroke-dashoffset: 283;
      transition: stroke-dashoffset 2s;
    }
    
    .circle-progress-text {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      font-size: 24px;
      font-weight: bold;
      text-align: center;
      /* Added to center the text */
    }
    
    .circle-progress-number-container {
      display: flex;
      align-items: baseline;
    }
    
    .circle-progress-number {
      transition: 2s;
    }
    
    .circle-progress-label {
      font-size: 12px;
      font-weight: normal;
      margin-top: -10px;
      /* Adjust the margin to separate the count up number and the word "Projects" */
    }
    
    .checkmark-container {
      position: absolute;
      top: -2px;
      /* Adjusted to lower the checkmark icon and circle */
      left: 50%;
      transform: translateX(-50%);
      opacity: 0;
      transition: opacity 0.5s, transform 0.5s;
    }
    
    .checkmark-circle {
      position: relative;
      width: calc(%id=iconSize%px + 5px);
      height: calc(%id=iconSize%px + 5px);
      background-color: white;
      border-radius: 50%;
      box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
    }
    
    .checkmark {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      stroke: deepskyblue;
      stroke-linecap: round;
    }
    
    @media screen and (-webkit-min-device-pixel-ratio:0) {
      .circle-progress-value {
        stroke: deepskyblue;
        stroke-dasharray: 283;
        stroke-dashoffset: 283;
        -webkit-transition: stroke-dashoffset 2s;
      }
    }
  </style>
</head>

<body>
  <div style="height: 150vh; background: pink; font-size: 72px;">PLEASE SCROLL DOWN</div>
  <div class="bar-container">
    <div class="circle-progress-container">
      <svg class="circle-progress" viewBox="0 0 100 100">
    <defs>
      <linearGradient id="circle-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
        <stop offset="0%" style="stop-color:red"/>
        <stop offset="100%" style="stop-color:blue"/>
      </linearGradient>
    </defs>
    <circle class="circle-progress-bg" cx="50" cy="50" r="45" stroke-width="1" fill="none" />
    <circle class="circle-progress-value" cx="50" cy="50" r="45" stroke-width="1" fill="none" />
  </svg>
      <div class="circle-progress-text">
        <div class="circle-progress-number-container" style="font-size: 40px;">
          <span class="circle-progress-number">50</span><span>+</span>
        </div>
        <div class="circle-progress-label" style="font-size: 14px;">Projects</div>
      </div>
      <div class="checkmark-container">
        <div class="checkmark-circle">
          <svg class="checkmark" width="16px" height="16px" viewBox="0 0 20 20">
        <polyline points="6,10 9,13 14,8" stroke-width="2" fill="none" />
      </svg>
        </div>
      </div>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', () => {
      const circleProgressBar = document.querySelector('.circle-progress-value');
      const circleProgressNumber = document.querySelector('.circle-progress-number');
      const checkmarkContainer = document.querySelector('.checkmark-container');
      const circleProgressContainer = document.querySelector('.circle-progress-container');

      const countUp = (start, end, element, duration) => {
        let current = start;
        const stepTime = Math.abs(Math.floor(duration / (end - start)));
        const timer = setInterval(() => {
          if (current <= end) {
            element.textContent = current++;
          } else {
            clearInterval(timer);
          }
        }, stepTime);
      };

      const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            circleProgressBar.style.transitionDuration = `2000ms`;
            circleProgressBar.style.strokeDashoffset = '0';
            countUp(0, 50, circleProgressNumber, 2000);
            setTimeout(() => {
              checkmarkContainer.style.opacity = '1';
            }, 2000);
          } else {
            circleProgressBar.style.strokeDashoffset = '283';
            circleProgressNumber.textContent = '0';
            checkmarkContainer.style.opacity = '0';
          }
        });
      }, {
        threshold: 0.5
      });
      observer.observe(circleProgressContainer);
    });
  </script>
</body>
</head>
A Haworth
  • 30,908
  • 4
  • 11
  • 14