HTML CSS JS

자바스크립트 클릭 이벤트를 이용한 물결 애니메이션 적용하기 / CSS, JS Animation

S_Hoon 2020. 8. 2. 00:29

물결표시 애니메이션 by using JS


FINAL CODE

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <script defer src="main.js"></script>
    <title>Ripple</title>
  </head>
  <body>
    <button>Hoon</button>
    <button>Hoon</button>
  </body>
</html>

CSS

* {
  margin: 0;
  padding: 0;
}

body {
  font-family: "Poppins", sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background-color: #040d15;
}

button {
  position: relative;
  padding: 50px 50px;
  margin: 10px;
  color: #fff;
  text-transform: uppercase;
  font-size: 18px;
  letter-spacing: 2px;
  border-radius: 40px;
  background: linear-gradient(90deg, #0162c8, #55e7fc);
  overflow: hidden;
  border: none;
  outline: none;
}
button:nth-child(2) {
  background: linear-gradient(90deg, #755bea, #ff72c0);
}

span {
  position: absolute;
  background-color: #fff;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%);
  animation: animate 1s linear;
}
@keyframes animate {
  0% {
    width: 0px;
    height: 0px;
    opacity: 0.5;
  }
  100% {
    width: 300px;
    height: 300px;
    opacity: 0;
  }
}

JS

const buttons = document.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    let x = e.clientX - e.target.offsetLeft;
    let y = e.clientY - e.target.offsetTop;

    const ripples = document.createElement("span");
    ripples.style.left = x + "px";
    ripples.style.top = y + "px";
    btn.appendChild(ripples);
  });
});

이 방식은 아래 유튜브에서 가져왔습니다

CSS, JS에 대한 기본적인 지식이 있으시다면 아래 영상을 바로 봐주시고 

영상이 잘 이해가 안간다면 이 글을 봐주시면 됩니다.

 

https://www.youtube.com/watch?v=ueyRcYEmsrI


ToDos

1. HTML에 button, div, a 중 하나를 골라 2개 생성, 셋 다 무난

2. CSS로 기본적인 UI 적용

3. 간단한 JS Logic을 이용해 클릭 이벤트 구현


1. HTML에 같은 Element 2개 생성하기

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <script defer src="main.js"></script>
    <title>Ripple</title>
  </head>
  <body>
    <button>Hoon</button>
    <button>Hoon</button>
  </body>
</html>

 

 

저는 button 두 개를 생성했습니다

<link rel="stylesheet" href="style.css" />
<script defer src="main.js"></script>

HTML 파일에 CSS, JS 파일을 연결시키는 것을 잊으면 안됩니다.

이 간단한 실수로 인해 쓸데없는 곳에서 삽푸고있을 가능성이 적지않습니다. 이런경우 개빡칩니다


2. CSS 작업하기

일단 첫 번째로

* {
  margin: 0;
  padding: 0;
}

위에 코드를 CSS 파일에 적으면 기본으로 브라우저가 가지고있는 기본값을 초기화 할 수 있습니다.

이것의 가장 베스트인 방법은 

https://meyerweb.com/eric/tools/css/reset/

 

CSS Tools: Reset CSS

CSS Tools: Reset CSS The goal of a reset stylesheet is to reduce browser inconsistencies in things like default line heights, margins and font sizes of headings, and so on. The general reasoning behind this was discussed in a May 2007 post, if you're inter

meyerweb.com

위에 링크에 들어간 뒤 코드블럭에 있는 코드를 복사하고

CSS 파일에 붙여넣기하면 완벅하게 기본값들을 초기화 할 수 있습니다

 

하지만 여기에서는 필요없으니 간단하게 2줄만 적으면 됩니다

 

2-1. Body 

body {
  font-family: "Poppins", sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background-color: #040d15;
}

body를 설정해줘야 합니다.

Line 1: font를 바꿔줍니다

Line 2: body안에 있는 모든 element들을 가로로 나열해줍니다

Line 3: Element들을 가로상(Horizental, row)에서의 중앙에 위치하게 해줍니다

Line 4: Element들을 세로상(vertical, column)에서의 중앙에 위치하게 해줍니다

Line 5: 위에 모든 것들이 제대로 동작하길 바란다면 body의 높이를 설정해줘야합니다. 사용자의 화면 크기만큼 높이가 늘어납니다

Line 6: body의 배경화면 색을 '#004d15' 설정합니다 (어두운 남색)

 

2-2. button 

button {
  position: relative;
  padding: 50px 50px;
  margin: 10px;
  color: #fff;
  text-transform: uppercase;
  font-size: 18px;
  letter-spacing: 2px;
  border-radius: 40px;
  background: linear-gradient(90deg, #0162c8, #55e7fc);
  overflow: hidden;
  border: none;
  outline: none;
}
button:nth-child(2) {
  background: linear-gradient(90deg, #755bea, #ff72c0);
}

뭐가 엄청 많으나 차분히 살펴보면 어려울 거 하나도 없습니다

 

button

Line 1: 이것은 나중에 JS 할 때 설명해 줄 것입니다

Line 2: button의 크기를 결정합니다. 아래, 위로 50px, 오른쪽, 왼쪽으로 50px

Line 3: button이 2개 있으나 서로 붙어있습니다. 떨어뜨려놔야 보기 좋습니다

Line 4: button안에 있는 글씨 색상을 바꿔줍니다

Line 5: 안에 있는 글씨를 대문자로 바꿔줍니다

Line 6: 글자 하나하나가 2px만큼의 거리를 두고 위치하게 만들어줍니다

Line 7: button이 원래 네모이지만 4개의 코너들을 둥글게 만들어줍니다

Line 8: 배경에 그라데이션을 넣어줍니다

Line 9: 이것도 나중에 JS 할 때 설명해 줄 것입니다

Line 10: button이 기본적으로 가지고있는 못생긴 테두리를 없애줍니다

Line 11: button을 눌렀을 때 나오는 네모난 테두리를 없애줍니다

 

button:nth-child(2) === button 2개중에 2번째를 건들것이다 라는 의미입니다

Line 1: button의 Line 8이랑 같은 의미이지만 다른 색을 부여합니다

 

linear-gradient에 들어가는 #000000, #000000

이것은 16진법으로 표현한 색상 코드입니다

linear-gradient와 어떤 16진법을 넣어야 하는지는 아래 글에 자세히 담겨져있습니다

2020/08/01 - [Useful Things] - uiGradients - 웹 퍼블리셔들에게 굉장히 유용한 웹사이트 / Gradation, Gradient Example

 

이쯤되면 이러한 화면이 보일것입니다

정중앙에 서로 다른 그라데이션을 가진 버튼 2개

이러한 화면이 나왔다면 잘하고 계신겁니다

 

뒤에 CSS 파일에 추가해야 할 부분들이 조금 남아있지만 JS 파트 설명해주면서 같이 알려드리겠습니다.


3. JS (JavaScript)

const buttons = document.querySelectorAll("button");

첫 번째로 DOM이라는 개념을 이용해서 HTML Element를 JS로 가져와야 그것을 컨트롤 할 수 있습니다.

위에 코드는 HTML에 있는 모든 button들을 상수 'buttons'에 담아라 라는 의미입니다.

 

이 다음에 우리는 함수를 만들어야하는데

그 함수가 button 하나가 아닌 모든 button들에게도 적용이 되어야하기 때문에 

forEach라는 함수안에 또 다른 함수를 적용할 것입니다.

const buttons = document.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
  });
});

첫 줄에 선언한 상수 다음에 

모든 버튼들에게 우리가 만들 함수가 적용될 수 있도록

forEach를 이용해 줍니다.

 

forEach에 들어가있는 'btn'이 왜 있는지 이해가 잘 안가신다면 아래 링크로 들어가시면 됩니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

 

Array.prototype.forEach()

The forEach() method executes a provided function once for each array element.

developer.mozilla.org

forEach 함수안에 첫 번째 줄인 'btn.addEventListener("click", (e))"는 

우리가 클릭했을 때 어떠한 함수를 실행하는 코드입니다.

const buttons = document.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    let x = e.clientX - e.target.offsetLeft;
    let y = e.clientY - e.target.offsetTop;
  });
});

  

 

우리가 button을 클릭했을 때 x, y라는 변수를 선언하는데 

x , y 가 가지는 값은 클릭했을 때에 마우스커서의 위치입니다.

e.target.offsetLeft, Top을 빼주는 이유는 

저것들을 빼주지 않으면 클릭했을 때에 

나중에 생성할 물결이 우리가 클릭한 곳이 아닌

button에서 더욱 먼 곳에서 생깁니다.

e.target.offsetLeft, Top의 의미는 버튼의 왼쪽 끝, 위쪽 끝의 좌표입니다.

 

이해가 안가신다면 괜찮습니다. 제가 설명을 못하는겁니다. 죄송합니다.

const buttons = document.querySelectorAll("button");

buttons.forEach((btn) => {
  btn.addEventListener("click", (e) => {
    let x = e.clientX - e.target.offsetLeft;
    let y = e.clientY - e.target.offsetTop;

    const ripples = document.createElement("span");
    ripples.style.left = x + "px";
    ripples.style.top = y + "px";
    btn.appendChild(ripples);
  });
});

그 아래에 ripples라는 상수를 선언해줍니다. 

ripples는 HTML 파일에 Element span을 만들라는 의미를 가집니다.

span은 물결이 될 것입니다. 

그렇게하기 위해서는 클릭할 때 span이 어떠한 좌표를 가져야하는지 설정해줘야 합니다.

 

ripples.style.left = x + "px"

ripples.style.top = y + "px"

 

미리 선언했던 x, y를 이용해서

ripples(span)의 좌표를 설정해줍니다.

 

가장 마지막줄에 있는 

btn.appendChild(ripples)를 해주지 않으면 그 전에 했던 모든 행동들이 의미가 없어집니다.

btn.appendChild(ripples), 이것은 우리가 button을 클릭할 때 마다 처음에 선언했던 각 buttons들에게 

span을 생성합니다.

 

이해가 잘 안가신다면 해당 HTML이 열려있는 브라우저에서 F12를 눌러보시고 'Elements'를 봐주세요.

클릭을 할 때마다 클릭한 button에 span이 생성되는 것을 보실 수 있습니다.


다시 CSS 작업

span {
  position: absolute;
  background-color: #fff;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%);
  animation: animate 1s linear;
}

span을 HTML에 생성을 했다면 

이제는 이 span을 이용해서 물결을 표현할 것입니다.

 

Line 1: css button Line 1 작업할 때 position: relative;를 보실 수 있습니다.

           여기에는 position: absolute;가 있습니다. 

           이렇게하면 spanbutton안에 생성될 것입니다.

           JS에서 좌표 변수를 선언할때 e.target.offsetLeft and Top을 빼준 이유가 이것입니다.

Line 2: span(물결)의 색상을 결정합니다. 

Line 3: span을 둥글게 만들어줍니다.

Line 4: span을 빠르게 클릭했을 시에 딜레이없이 span이 생성되게 도와줍니다. 

            pointer-events에 대해 더 알고싶다면 아래 링크로 들어가시면 됩니다.

            https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events

Line 5: button을 클릭했을 때 마우스포인터를 중심으로 span이 생성됩니다.

Line 6: span이 갑자기 생성되는 것이 아니라 물결처럼 천천히 생기도록 애니메이션을 추가해줍니다.

@keyframes animate {
  0% {
    width: 0px;
    height: 0px;
    opacity: 0.5;
  }
  100% {
    width: 300px;
    height: 300px;
    opacity: 0;
  }
}

 위에 코드 바로 아래에 이 코드를 생성해줍니다.

@keyframes는 위에 적용했던 애니메이션이 어떤식으로 작동해야 하는지 결정해줍니다.

첫 줄에 animate는 변수이름 같은 것입니다. 얼마든지 바뀔 수 있습니다. 원하는 변수명으로 해주십시오.

 

0%의 의미는 애니메이션이 어떻게 시작되는지를 결정합니다.

width 0, height 0과 opacity(투명도)를 이용해 

크기는 0부터, 투명도는 중간부터 시작하도록 해줍니다.

opacity(투명도)의 최댓값은 1입니다. 0이 최소값입니다.

 

100%의 의미는 애니메이션이 어떻게 끝날지를 결정합니다.

width 300, height 300, opacity 0의 의미는

span을 가로세로 300px까지 커지면 애니메이션을 끝내라는 의미입니다. 투명도는 0이므로 안보이게됩니다.


완성

물결표시 애니메이션 by using JS

이해가 잘 안가신다면 그것이 정상입니다. 포기하지마세요.

CSS 코드 한줄 한줄 지워가면서 "이게 왜 이렇게되지?"라는 궁금증을 없앨 수 있길 바랍니다.

 

JS 코드가 이해가 안가신다면

console.log(); 를 통해 변수 x, y가 뭔지 e.target.offsetLeft 등이 뭔지 알 수 있습니다.