본문 바로가기

Vanilla Javascript Effect 구현

Vanilla Javascript Effect 무작정 따라하기 #1 typing effect

반응형

2021.04.10 - [개인공부] - 2021년 4월 10일 to do list

 

2021년 4월 10일 to do list

[JS/Node 기초] Checkpoint 복습 Sprint Review[JS/Node]를 통한 이해도 체크 후 부족한 부분 학습 Coplit 깊은 탐구(+ reference의 코드분석) 오류부터 해결까지 전 과정을 나타내었다. Vanilla Javascript Effec..

bedeveloper.tistory.com

2021.04.09 - [코드스테이츠] - 2021년 4월 9일 코드스테이츠 DAY-5(HTML)( + 일주일 솔직 후기)

 

2021년 4월 9일 코드스테이츠 DAY-5(HTML)( + 일주일 솔직 후기)

웹개발 이해하기(Chapter) : HTML기초 Solo Study(변수 ~ 반복문, HTML/CSS) 동기부여 세션(Zoom) + 코드스테이츠 1주차 솔직 후기 블로그 관리 방향 동기부여 세션(Zoom) : 코드스테이츠에서 개발자로의 취업

bedeveloper.tistory.com

이전 글들에서 앞으로 무엇을 공부하고 포스팅해야 나에게도 보는이에게도 의미가 있을까 고민을 했었었다.

 

그리하여 결정한 것은 vanilla javascript로 움직이는 어떤 것(재밌는 것)을 만들어보고 올리자라는 것.

(나의 뜻으로 무엇인가를 움직이게 한다는 것은 얼마나 신기하고 재밌지 않은가?)

온전히 나의 생각으로 만드는 것이 아니지만 따라하다보면 나중에 도움이 될 것이라 판단을 했다.

 

코드스테이츠를 시작하기 전부터 interaction을 구현하는 것에 관심을 가지고 꾸준히 따라했었지만 

 

코드스테이츠를 시작하고 나서는 시간적 여유가 없어서 못해오고 있었다.

 

주말을 활용해서 하고싶은 것을 할 수 있어서 참 다행이다.

 

자 얼른 얼른 시작하자. 

 

우선 어떤 효과를 해볼지 유투브에 vanilla javascript effect를 검색하였다. 

 

링크 주소: https://youtu.be/PuOGBacTYAY

굉장히 감성있는 썸네일이 있다.

 

Dev Ed 라는 유튜버는 외국에서 꽤나 유명한 developer인데 구독해두고 종종 들어가 재밌는 것들을 따라하고 했었기에

 

이사람의 것을 한번 따라쳐보기 시작했다. 

 

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="main.css">
    <title>Document</title>
</head>
<body>
    <div class="intro">
        <h1>나나야 I want to go</h1>
        <h1 class="typing" > hi</h1>
    </div>
    <script src="main.js"></script>

</body>
</html>

 

CSS

 

body{
    font-family: sans-serif;
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.intro{
    display: flex;
    color: white;
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./samuel-berner-f5xRg0r7MME-unsplash.jpg);
    background-size: cover;
}

.typing{
    margin-left: 10px;
    position: relative;
}
//.typing::after로 타자칠때 생기는 깜빡이는 효과를 나타냈다.
.typing::after{
    content: "";
    position: absolute;
    right: -5px;
    width: 1px;
    height: 5%;
    border-right: 2px solid white;
    animation: blink 0.5s infinite ease;
}

@keyframes blink {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

 

Javascript

 

const texts = ['KYOTO', 'FUKUOKA', 'OKINAWA']
let count = 0;
let index = 0;
let currentText = '';
let letter = '';

(function type(){

if(count === texts.length){
    count = 0;
}
currentText = texts[count];
letter = currentText.slice(0,++index);
 
document.querySelector('.typing').textContent = letter;
if(letter.length === currentText.length){
    count++;
    index = 0; 
}
setTimeout(type, 800);
}());

//1.타자 효과를 내고 싶은 단어들을 배열에 담는다.
//2.배열의 단어를 다음 단어로 옮겨 줄 변수(count)를 하나 선언하고 0을 할당하자. 
//3.단어 속에서 글자를 다음 글자로 옮겨 줄 변수(index)를 하나 선언하고 0을 할당하자.
//4.타자 효과가 진행중인 단어를 나타내는 변수(currentText)를 선언하고 빈문자열을 할당한다.
//5.타자 효과가 진행중인 글자를 나타내는 변수(letter)를 선언하고 빈문자열을 할당한다.
//6.타자기능을 구현할 함수 type을 선언한다.
//7.배열에 담긴 단어가 맨끝의 단어일 경우 처음으로 돌아오도록 if문을 작성한다.
//8.현재단어를 count를 통해 정의 해준다.
//9.현재 출력된 글자를 나타내는 letter를 정의 해준다.
//10.letter의 길이와 현재단어의 길이와 같다면 count를 ++하여 다음 단어로 넘어가게 한다.
//11.index를 0으로 초기화하여 다음단어가 처음 글자부터 출력되게 한다.
//12.함수를 닫는다. 
//13.이 함수를 setInterval을 통해 시간을 두고 실행하도록 한다.

사진이라던지 적고 싶은 말은 나의 취향에 맞게 적어봤다. 

 

그리고 자바스크립트의 원리를 알아보기 위해서 pseudo code를 역으로 작성해 봤다. 적어보면서 원리를 알게 된 것같다. 

 

자 HTML을 열었을 때의 모습을 보자.

 

 

일본 여행이 가고싶어서 이렇게 만들어 보았다. 

여담이지만 나나야는 내 아내의 애칭이다. 그리고 내 아내는 재일교포라서 일본에서 태어났다.

 

아내를 만나서 일본을 많이 가게됬는데 갈때마다 즐거운 추억을 많이 쌓고왔다! 

 

아무튼 지금의 웹도 나쁘지 않지만 몇가지 더 추가하고 싶은게 생겼다.

 

  • 도시의 이름만 나왔으면 좋겠다.
  • 도시의 이름이 컸으면 좋겠고 화면 가운데 위치했으면 좋겠다.
  • 도시의 이름이 바뀔때마다 그 도시의 사진이 출력됬으면 좋겠다.

한번 바꾸어 보겠다.

 

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="main.css">
    <title>Document</title>
</head>
<body>
    <div class="intro">
        <!-- <h1>나나야 I want to go</h1> --> 
        <!-- 이 부분을 주석처리하여서 도시이름만 나오도록 만들었다. -->
        <h1 class="typing" > hi</h1>
    </div>
    <script src="main.js"></script>

</body>
</html>

 

 

CSS

 

body{
    font-family: sans-serif;
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.intro{
    display: flex;
    justify-content: center; /* 추가 : 화면의 중앙에 위치 */
    align-items: center;/* 추가: 화면의 중앙에 위치 */
    color: white;
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./samuel-berner-f5xRg0r7MME-unsplash.jpg);
    background-size: cover;
}

.typing{
    margin-left: 10px;
    position: relative;
    font-size: 15vh;/* 추가 : 글자크기 확대 */
}

.typing::after{
    content: "";
    position: absolute;
    top: 4vh;/*추가 : 글자의 위치와 크기를 바꾸니 깜빡이는 위치가 바뀌어서 수정하였다.*/
    right: -1vh; /*수정*/
    width: 10px; /*수정 : 글자의 크기가 커집에 따라 수정하였다.*/
    height: 15vh; /*수정 : font-size에 맞추어 수정*/
    border-right: 2px solid white;
    animation: blink 0.5s infinite ease;
}

@keyframes blink {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

위 HTML, CSS 수정으로 

 

  • 도시의 이름만 나왔으면 좋겠다.
  • 도시의 이름이 컸으면 좋겠고 화면 가운데 위치했으면 좋겠다.

위 두가지 기능은 이루었다. 중간 결과를 확인해 보자.

 

 

도시의 이름만나오게 그리고 텍스트를 가운데로 위치시켰다.

 

관건은 텍스트에따라 어떻게 배경화면을 바꿀까라는 것이다. 

 

당장에 떠오르는 것은 화면이 바뀔때마다 setAttribute로 아이디값을 지정해 주고, 그 아이디 값에 따라 CSS를 변경시키는 것이다. 

 

말로하니 나도 무슨말인지 모르겠다. 코드로 한번 보자.

 

Javascript

 

const texts = ['KYOTO', 'FUKUOKA', 'OKINAWA']
let count = 0;
let index = 0;
let currentText = '';
let letter = '';

(function type(){

if(count === texts.length){
    count = 0;
}
currentText = texts[count];
letter = currentText.slice(0,++index);
 
document.querySelector('.typing').textContent = letter;
if(letter.length === currentText.length){
    count++;
    if(count === 3){ 
        count = 0;  // count가 3이되면 0으로 다시 리셋되게하여 id값이 3으로 되지않도록 하였다.
    }
    index = 0; 

    document.querySelector('.intro').setAttribute('id', `changeBackground-${count}`); //한 단어가 끝나서 다음 단어로 넘어갈때 아이디 값을 세팅해 주었다.
}
setTimeout(type, 800);
}());

 

 

CSS

 

body{
    font-family: sans-serif;
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.intro{
    display: flex;
    justify-content: center; 
    align-items: center;
    color: white;
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./0.jpg);
    background-size: cover;
    transition: 1s ease-in-out 1s;
}

#changeBackground-1{  /* 추가 : 새로운 id가 붙을 때마다 새로운 배경화면을 세팅해주었다. */
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./1.jpg);
    background-size: cover;
}
#changeBackground-2{  /* 추가 : 새로운 id가 붙을 때마다 새로운 배경화면을 세팅해주었다. */
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./2.jpg);
    background-size: cover;
}
#changeBackground-0{  /* 추가 : 새로운 id가 붙을 때마다 새로운 배경화면을 세팅해주었다. */
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./0.jpg);
    background-size: cover;
}

.typing{
    margin-left: 10px;
    position: relative;
    font-size: 15vh;
}

.typing::after{
    content: "";
    position: absolute;
    top: 4vh;
    right: -1vh; 
    width: 10px; 
    height: 15vh;
    border-right: 2px solid white;
    animation: blink 0.5s infinite ease;
}

@keyframes blink {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

수정 결과를 한번 보자

 

 

 

배경화면이 바뀌긴 바뀌는데 의도치 않게 해당 도시의 글자가 다 끝나기도 전에 다음 도시의 사진으로 바뀌어버린다.

또한 바뀔 때 너무 팍팍 바뀌어서 웹이 못생겼다.

 

  • 도시의 글자가 끝나기전에 다음 도시의 배경으로 바뀌는 것을 조정하겠다.
  • animation을 사용하여 background 이미지가 smooth하게 바뀌게 하겠다.

위 내용을 적용한 코드 및 동영상을 보자

 

CSS

 

body{
    font-family: sans-serif;
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    width: 100vw;
    height: 100vh;
    position: relative;
}

.intro{
    display: flex;
    justify-content: center; 
    align-items: center;
    color: white;
    height: 100vh;
    background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url(./0.jpg);
    background-size: cover;
    transition: all 1s ease-in-out;     /* 자연스러운 배경 변화를 위해 transition을 넣었다. */
}

#changeBackground-0{
    height: 100vh;
    background: url(./0.jpg);
    background-size: cover;
}
#changeBackground-1{
    height: 100vh;
    background: url(./1.jpg);
    background-size: cover;
}
#changeBackground-2{
    height: 100vh;
    background: url(./2.jpg);
    background-size: cover;
}

.typing{
    margin-left: 10px;
    position: relative;
    font-size: 15vh;
}

.typing::after{
    content: "";
    position: absolute;
    top: 4vh;
    right: -1vh; 
    width: 10px; 
    height: 15vh;
    border-right: 2px solid white;
    animation: blink 0.5s infinite ease;
}

@keyframes blink {
    0% {
        opacity: 0;
    }
    100% {
        opacity: 1;
    }
}

 

 

Javascript

 

const texts = ['KYOTO', 'FUKUOKA', 'OKINAWA']
let count = 0;
let index = 0;
let currentText = '';
let letter = '';

(function type(){

if(count === texts.length){
    count = 0;
}

currentText = texts[count];

document.querySelector('.intro').setAttribute('id', `changeBackground-${count}`); //이전 도시의 이름이 끝난 후 다음 글자가 시작되기 직전에 id를 붙여주어 다음 글자와 동시에 시작하도록 조정하였다.

letter = currentText.slice(0,++index);
 
document.querySelector('.typing').textContent = letter;
if(letter.length === currentText.length){
    count++;
    if(count === 3){ 
        count = 0;
    }
    index = 0; 
}
setTimeout(type, 800);
}());

 

 

 

 

 드디어 의도한 대로 동작이 이루어진다!  background가 바뀌는 타이밍을 찾는 것은 쉬웠지만, transition을 넣는 것을 생각 못하고 animation으로 구현하려다 보니 시간을 엄청 잡아먹었다. 하지만 마지막은 원하는 결론을 도출하였기에 유익한 삽질이었다. 

답은 꽤나 쉽고 가까운곳에 있음을 한번 더 느끼게된다.  

 

따라하는 것은 쉽다. 근데 나의 입맛에 맞게끔 바꾸는 과정에서 예상치 못한 동작들이 많이 나타났다. 응용이 어렵다. 

 

다음 주에도 재밌고 유익한 vanilla javascript effect로 찾아오겠다. 

반응형