10 스킬바
1. 스킬바 막대형
- 지시문
- HTML
- CSS
- JS
1<div class="content">contents</div>2<div class="animation">3 <div class="progress-bar">4 <div class="bar"></div>5 <div class="rate" data-rate="30"></div>6 </div>7 <div class="progress-bar">8 <div class="bar"></div>9 <div class="rate" data-rate="90"></div>10 </div>11 <div class="progress-bar">12 <div class="bar"></div>13 <div class="rate" data-rate="60"></div>14 </div>15</div>16<div class="content">contents</div>1 .progress-bar {2 position: relative;3 width: 960px;4 height: 30px;5 margin: 3em auto;6 border: 1px solid green;7 }8 .progress-bar .bar {9 position: absolute;10 left: 0;11 top: 0;12 bottom: 0;13 width: 0;14 background: green;15 }16 .progress-bar .rate {17 position: absolute;18 top: 0;19 right: 15px;20 bottom: 0;21 line-height: 30px;22 font-size: 1.2em;23 color: green;24 }25 .content {26 height: 800px;27 font-size: 3em;28 }1 $(function () {2 var progressWrap = $('.progress-bar');3 var animationOst = $('.animation').offset().top - 600;4 var isAni = false;5 $(window).scroll(function () {6 if ($(window).scrollTop() >= animationOst && !isAni) {7 progressAnimation();8 }9 });10
11 function progressAnimation() {12 progressWrap.each(function () {13 var $this = $(this),14 progressBar = $this.find('.bar'),15 progressText = $this.find('.rate'),16 progressRate = progressText.attr('data-rate');17 progressBar.animate({ width: progressRate + '%' }, 2500);18 // console.log(progressText);19 var text = function () {20 $({ rate: 0 }).animate(21 { rate: progressRate },22 {23 duration: 2000,24 progress: function () {25 var now = this.rate;26 console.log(now);27 progressText.text(Math.floor(now) + '%');28 },29 complete: function () {30 isAni = true;31 },32 }33 );34 };35 text();36 });37 }38 });1.1. 스킬바 원형
- HTML
- CSS
- JS
1<section>2 <h2>content</h2>3</section>4<div class="charts">5 <div class="chart">6 <h2 data-num="20">0</h2>7 <svg>8 <circle cx="110" cy="110" r="100"></circle>9 </svg>10 </div>11 <div class="chart">12 <h2 data-num="60">0</h2>13 <svg>14 <circle cx="110" cy="110" r="100"></circle>15 </svg>16 </div>17 <div class="chart">18 <h2 data-num="80">0</h2>19 <svg>20 <circle cx="110" cy="110" r="100"></circle>21 </svg>22 </div>23 <div class="chart">24 <h2 data-num="50">0</h2>25 <svg>26 <circle cx="110" cy="110" r="100"></circle>27 </svg>28 </div>29</div>30<section>31 <h2>content</h2>32</section>1 .charts {2 width: 80%;3 margin: 3rem auto;4 display: flex;5 justify-content: center;6 }7 .charts .chart {8 margin: 0 20px;9 position: relative;10 }11 .charts .chart h2 {12 position: absolute;13 left: 50%;14 top: 50%;15 transform: translate(-50%, -50%);16 margin: 0;17 }18 .charts .chart svg {19 width: 220px;20 height: 220px;21 }22 circle {23 fill: #ffffff;24 stroke-width: 20;25 stroke-dasharray: 628;26 stroke-dashoffset: 628;27 /* animation:line 2s forwards; */28 transform: rotate(-90deg);29 transform-origin: 50% 50%;30 stroke-linecap: round;31 }32 @keyframes line {33 from {34 stroke-dashoffset: 628;35 }36 to {37 stroke-dashoffset: 0;38 }39 }40 .charts .chart:nth-child(1) circle {41 stroke: #ffc114;42 }43 .charts .chart:nth-child(2) circle {44 stroke: #ff5248;45 }46 .charts .chart:nth-child(3) circle {47 stroke: #19cdca;48 }49 .charts .chart:nth-child(4) circle {50 stroke: #4e88e1;51 }52
53 section {54 height: 100vh;55 }56
57 line {58 stroke: #4e88e1;59 }1$(function () {2 var charts = $('.charts');3 var chart = $('.chart');4 var chartOST = chart.offset().top - 700;5 // var excuted = false;6 // console.log(excuted);7
8 $(window).scroll(function () {9 var currentSCT = $(this).scrollTop();10 if (currentSCT >= chartOST) {11 if (!charts.hasClass('active')) {12 animateChart();13 charts.addClass('active');14 }15 }16 });17
18 function animateChart() {19 chart.each(function () {20 var item = $(this);21 var title = item.find('h2');22 var targetNum = title.attr('data-num');23 var circle = item.find('circle');24
25 $({ rate: 0 }).animate(26 { rate: targetNum },27 {28 duration: 1500,29 progress: function () {30 var now = this.rate;31 var amount = 630 - (630 * now) / 100;32
33 title.text(Math.floor(now));34 circle.css({ strokeDashoffset: amount });35 },36 }37 );38 }); //chart each39 }40});1.2. 막대형2
- 지시문
- HTML
- CSS
- JS
1 <section>2 <h2>content</h2>3 </section>4 <div class="charts">5 <div class="chart">6 <h2 data-num="20">0</h2>7 <svg>8 <line x1="0" y1="0" x2="500" y2="0"></line>9 </svg>10 </div>11 <div class="chart">12 <h2 data-num="20">0</h2>13 <svg>14 <line x1="0" y1="0" x2="500" y2="0"></line>15 </svg>16 </div>17 <div class="chart">18 <h2 data-num="80">0</h2>19 <svg>20 <line x1="0" y1="0" x2="500" y2="0"></line>21 </svg>22 </div>23 </div>24 <section>25 <h2>content</h2>26 </section>1.charts {2 width: 80%;3 margin: 3rem auto;4 display: flex;5 justify-content: center;6}7
8.charts .chart {9 margin: 0 20px;10 position: relative;11}12
13.charts .chart h2 {14 position: absolute;15 left: 50%;16 top: 50%;17 transform: translate(-50%, -50%);18 margin: 0;19}20
21line {22 fill: #ebebeb;23 stroke-width: 20;24 stroke-dasharray: 300;25 stroke-dashoffset: 300;26}27
28/* @keyframes line {29 from {stroke-dashoffset: 628;}30 to {stroke-dashoffset: 0;}31} */32.charts .chart:nth-child(1) line {33 stroke: #ffc114;34}35
36.charts .chart:nth-child(2) line {37 stroke: #ff5248;38}39
40.charts .chart:nth-child(3) line {41 stroke: #19cdca;42}43
44.charts .chart:nth-child(4) line {45 stroke: #4e88e1;46}47
48section {49 height: 100vh;50}51
52line {53 stroke: #4e88e1;54}1var charts = $('.charts');2var chart = $('.chart');3var chartOST = chart.offset().top - 700;4// var excuted = false;5// console.log(excuted);6
7$(window).scroll(function () {8 var currentSCT = $(this).scrollTop();9 if (currentSCT >= chartOST) {10 if (!charts.hasClass('active')) {11 animateChart();12 charts.addClass('active');13 }14 }15});16
17function animateChart() {18 chart.each(function () {19 var item = $(this);20 var title = item.find('h2');21 var targetNum = title.attr('data-num');22 var circle = item.find('line');23
24 $({ rate: 0 }).animate(25 { rate: targetNum },26 {27 duration: 1500,28 progress: function () {29 var now = this.rate;30 var amount = 300 - (300 * now) / 100;31
32 title.text(Math.floor(now));33 circle.css({ strokeDashoffset: amount });34 },35 }36 );37 }); //chart each38}2. with GSAP
gsap 을 사용해보자
1<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>2<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>- html
1<div class="circular-pbar">2 <span class="circular-pbar-counter">0</span>3</div>- css
1.circular-pbar {2 width: 200px;3 height: 200px;4 border-radius: 50%;5 background: conic-gradient(darkred 33%, 0, black);6 position: relative;7}8.circular-pbar-counter {9 position: absolute;10 font-size: 3em;11 color: white;12 top: 50%;13 left: 50%;14 transform: translate(-50%, -50%);15}- css
요약
.circular-pbar 그라디언트 색상변경
지역변수 —p 선언후 0 할당 배경으로 grey 색상을 지정하고 색상의 location에 변수를 할당한다.
1.circular-pbar {2 --p: 0;3 background: conic-gradient(#df3030 var(--p, 0), 0, #cacaca);4}- js :::note gsap.to 를 사용하여 변수 p의 값인 location 을 변경한다 :::
1gsap.to('.circular-pbar', {2 '--p': '33%',3 duration: 4,4 ease: 'expo.out',5});참고
숫자를 애니메이트 해보자
1const circles = document.querySelectorAll('.circular-pbar');2circles.forEach((el) => {3 const counter = el.querySelector('.circular-pbar-counter');4 const tg = counter.textContent + '%';5
6 const tm = gsap.timeline({7 defaults: { duration: 4, ease: 'expo.out' },8 scrollTrigger: {9 trigger: el,10 toggleActions: 'play pause resume reset',11 },12 });13
14 tm.from(counter, {15 textContent: 0,16 modifiers: {17 textContent: (textContent) => {18 return textContent.toFixed();19 },20 },21 });22 tm.to(el, { '--p': tg }, 0);23});- #4- counter 요소의 텍스트(목표 진행률 값)을 읽어와서 ’%’ 문자와 결합. 이 값은 나중에 CSS 변수로 사용됨.
- #6~7- GSAP 타임라인 생성 후 기본값으로 지속 시간(4초), 가속도 효과(‘expo.out’) 할당
- #16 - modifiers 플러그인은 gsap 의 기본으로 내장된 것으로 특정속성의 변경값을 실시간으로 수정해준다.
- 모든 애니메이션에 사용 가능하며 개발자가 원하는 모든 속성에 적용할수 있다.
- 이때 함수를 사용해야 한다.