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 파일에 붙여넣기하면 완벅하게 기본값들을 초기화 할 수 있습니다
하지만 여기에서는 필요없으니 간단하게 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
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;가 있습니다.
이렇게하면 span이 button안에 생성될 것입니다.
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이므로 안보이게됩니다.
완성
이해가 잘 안가신다면 그것이 정상입니다. 포기하지마세요.
CSS 코드 한줄 한줄 지워가면서 "이게 왜 이렇게되지?"라는 궁금증을 없앨 수 있길 바랍니다.
JS 코드가 이해가 안가신다면
console.log(); 를 통해 변수 x, y가 뭔지 e.target.offsetLeft 등이 뭔지 알 수 있습니다.