새소식

인기 검색어

JAVASCRIPT & jQuery

무한 롤링 배너

  • -

웹사이트에서 많이 사용되는 배너 방식이 '텍스트 롤링' 배너이다.

여러 개의 텍스트 내용 행, 또는 아이템을 가로나 세로 방향으로 무한 회전하면서 내용을 넘겨가면서 보여주는 배너이다.

 

무한 롤링 배너를 만드는 방법은 CSS 키프레임 애니메이션으로 만드는 방법과, 자바스크립트로 만드는 방법으로 구분할 수 있다.

각각 장단점이 있기 때문에 어떤 방법이 더 낫다고 할 수는 없고, 용도에 맞춰 구현 방법을 선택하면 된다.

구현 난이도는 CSS 키프레임 애니메이션을 이용하는 방식이 가장 쉽다.

 


1.  무한 롤링 배너의 동작 방식 이해하기

무한 롤링 배너는 배너가 돌면서 무한 회전하는 듯한 느낌을 만드는 것이 핵심이다.

배너가 한쪽 방향으로 끝까지 이동한 후 처음 시작 위치로 점프해서 다시 진행하는 배너보다는 훨씬 더 자연스러운 배너를 표현할 수 있다.

 

무한 롤링 배너를 만들기 위해서는 2개의 배너가 필요한데

HTML로 2개를 전부 생성하지 않고, 한 개만 만들어서 자바스크립트를 이용해 복제할 것이다.

기본적으로는 배너 길이가 뷰포트 너비보다는 길어야 자연스러운 배너 롤링이 구현된다.

 

무한 롤링 배너는 다음과 같은 순서로 동작한다.

 

 

 

복제 배너는 원본 배너가 왼쪽 바깥 영역으로 완전히 이동하면서 생기는 배너 뷰포트 영역의 빈 공간을 채워 들어오는 역할을 한다.

실제로는 같은 데이터를 가진 배너 2개가 번갈아가면서 뷰포트를 채우면서 왼쪽으로 이동하는 것이지만, 실제 동작은 하나의 배너가 무한 롤링을 하는 것처럼 보인다.

 

무한 롤링 배너를 구현하는 핵심은 3번의 배너1 위치를 오른쪽 바깥 영역으로 이동하는 것이다.

CSS 키프레임 애니메이션, 또는 자바스크립트로 롤링 배너를 구현할 때 이 부분은 별도로 예외처리를 하게 된다.

 

 

 


2.  무한 롤링 배너 기본 HTML

 

무한 롤링 배너는 배너 내용이 표시되는 뷰포트 영역과, 뷰포트 영역 안에서 흘러가는 배너 내용 부분 2가지로 구분된다.

실제로는 배너 내용을 자바스크립트로 복제해서 2개의 배너 내용으로 사용하게 되지만, 뷰포트 영역은 뷰포트 영역 바깥에 있는 배너 내용은 보이지 않도록 하는게 포인트다.

따라서 뷰포트 요소에는 "overflow: hidden" 속성을 부여해서 원하지 않는 부분이 보이지 않도록 해야 하는데

에제에서는 ".group-rolling" 클래스로 감싼 요소가 뷰포트 영역의 역할을 하게 된다.

 

<section class="sc-banner">
    <div class="rollingbaner"><!-- "배너 전체 선언자" -->
        <div class="group-rolling"><!-- "배너 뷰포트" -->
            <div class="rolling-area"><!-- "배너 내용 래퍼" -->
                <ul class="rolling-list">
                    <li class="rolling-item">
                        <svg version="1.1" id="svg-roll1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1698px" height="114px" viewBox="0 0 1698 114" enable-background="new 0 0 1698 114" xml:space="preserve"></svg>
                    </li>
                    <li class="rolling-item">
                    	<svg version="1.1" id="svg-roll2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1744px" height="114px" viewBox="0 0 1744 114" enable-background="new 0 0 1744 114" xml:space="preserve"></svg>
                    </li>
                </ul>
            </div>
        </div>
    </div>
</section>

 

 

그림으로 표현하면 다음과 같이 배너 초기 상태가 만들어진다.

 

 

 

이 배너의 배너1(배너 내용)을 자바스크립트로 복제 배너를 만들어 배너1 옆에 배치해서 롤링할 수 있는 구조를 만들게 된다.

 

 


3-1.  무한 롤링을 위한 클론 배너 생성

clonNode() 메서드로 복제 요소를 생성해서 appendChild() 메서드로 상위 요소의 맨 끝 자식 요소로 붙여 넣는 간단한 자바스크립트 코드이다.

"roller1", "roller2" ID를 부여하고 "original", "clone" 클래스를 부여하는 것은 편의를 위해 사용했다. 실제로는 둘 중 하나만 사용해서 원본 배너와 복제 배너를 식별해서 사용하는데 아무런 문제가 없다.

cloneNode() 메서드로 복제 요소를 생성할 때는 꼭 파라메터로 "true"를 넣어서 하위 자식 노드들까지 모두 복제가 되도록 해야한다.

 

//롤링 배너 복제본 생성
let roller = document.querySelector('.roller');
roller.id = 'roller1';

let clone = roller.cloneNode(true);
clone.id = 'roller2';
document.querySelector('.wrap').appendChild(clone); //부착

//원본, 복제본 배너 위치 지정
document.querySelector('#roller1').style.left = '0px';
document.querySelector('#roller2').style.left = document.querySelector('.roller ul').offsetWidth+'px';

//클래스 할당
roller.classList.add('original');
clone.classList.add('clone');

 

 

 


3-2.  CSS 키프레임 애니메이션으로 무한 회전 구현하기

원본 배너와 복제해서 생성한 배너에 키프레임 애니메이션을 추가해서 무한 회전하는 애니메이션을 추가한다.

애니메이션은 2개를 만들어야 하고, 원본 배너와 복제 배너의 시작 위치가 다르기 때문에 애니메이션 루프의 이동 크기와 좌표가 다르다.

 

rollingleft1 은 원본 배너, rollingleft2는 복제 배너용이다.

 

먼저 복제 배너용은 오른쪽 바깥의 시작 위치에서 배너 2개 너비만큼 왼쪽으로 주욱 이동하고 종료한다.

이때 중요한 점은 이동 크기(translateX(-200%))를 픽셀 단위로 표기하지 않아도 된다.

퍼센트 값으로 배너 자신의 너비를 알 수 있기 때문에 배너 너비를 기준으로 이동 크기를 정할 때는 퍼센트 값으로 표기를 하면 된다.

 

원본 배너는 애니메이션 시작 시점에 기본으로 표시되는 배너이다.

배너 너비만큼 왼쪽으로 이동해서 안 보이게 되면 오른쪽 바깥 안 보이는 위치로 순간 이동을 한 후 다시 배너 너비만큼 왼쪽으로 이동해서 초기 시작 위치에서 멈춘다.

 

중요한 키포인트는 애니메이션 중간에 왼쪽 바깥 위치에서 오른쪽 바깥 위치로 순간 이동을 하는 것이다.
애니메이션 진행 정도는 소수점 둘째 자리까지 표시할 수 있고, 소수점 둘째 자리 애니메이션은 진행 속도는 아주 짧은 순간이기 때문에 아주 아주 느린 애니메이션이 아닌 이상 순간이동을 하게 되어 보이지 않는다.

 

50% 애니메이션 진행 시점에 배너가 가져져서 안 보이게 되는 위치만큼 왼쪽으로 이동한 후, 50.01% 시점에 오른쪽 가려져서 안 보이는 위치로 배너가 순간 이동을 하게 된다.

그리고 100% 시점까지 배너가 자시 왼쪽으로 배너 너비만큼 이동한 후 멈추게 된다.

 

복잡하게 구현을 하자면 애니메이션 2개를 조합해서 만들 수도 있지만, 구조가 복잡해지기 때문에 유지보수 하기가 그만큼 어려워지게 된다.

관리가 안 되는 코드는 그냥 쓰레기이므로 구조가 이해하기 쉽고 관리하기 편한 단일 애니메이션이 많이 사용된다.

 

/* 애니메이션 */
.roller.original{
    animation: 33s linear 0s infinite normal forwards running rollingleft1;
}
.roller.clone{
    animation: 33s linear 0s infinite normal none running rollingleft2;
}
@keyframes rollingleft1 { /* 원본용 */
    0% {
        transform: translateX(0);
    }
    50% {
        transform: translateX(-100%);
    }
    50.01%{
        transform: translateX(100%);
    }
    100%{
        transform: translateX(0);
    }
}

@keyframes rollingleft2 { /* 클론용 */
    0% {
        transform: translateX(0);
    }
    100% {
        transform: translateX(-200%);
    }
}

 


4.  자바스크립트로 무한 회전 구현하기

디자인은 앞서 만든 것을 그대로 사용하며 애니메이션만 키프레임 애니메이션을 대신해서 자바스크립트로 구현하는 코드이다.

먼저 CSS 코드에서 앞서 구현한 키프레임 애니메이션 부분만 삭제한다.

 

그리고 다음의 자바스크립트 코드를 복제본 배너를 생성하는 자바스크립트 뒤에 추가로 작성한다.

 

//인터벌 메서드로 애니메이션 생성
let rollerWidth = document.querySelector('.roller ul').offsetWidth;//회전 배너 너비값
let betweenDistance = 1;//이동 크기 - 정수여야 함
originalID = window.setInterval(betweenRollCallback, parseInt(1000/100), betweenDistance, document.querySelector('#roller1'));
cloneID = window.setInterval(betweenRollCallback, parseInt(1000/100), betweenDistance, document.querySelector('#roller2'));

//인터벌 애니메이션 함수(공용)
function betweenRollCallback(d, roller){
    let left = parseInt(roller.style.left);
    roller.style.left = (left - d)+'px';//이동
    //조건부 위치 리셋
    if(rollerWidth + (left - d) <= 0){
        roller.style.left = rollerWidth+'px';
    }
}

 

작성된 코드는 일정 시간으로 반복 실행되는 인터벌(setInterval()) 메서드 2개를 생성해서 원본과 복제본 배너 2개를 반복 이동시키는 애니메이션을 생성한다.

이동 콜백 함수(betweenRollCallback)는 배너 객체를 파라메터(두 번째 파라메터인 roller)로 넘겨서 공용으로 사용할 수 있도록 한 개로 만든다.

 

자바스크립트 롤링 코드에서 중요한 주의사항은 딱 두 가지가 있다.

 

> 첫 번째, betweenDistance 변수

인터벌 메서드가 실행될 때마다 배너가 이동하는 크기를 결정한다.

지나치게 계산적인 나머지 1초에 60번 인터벌을 호출하고 30초 동안 루프를 한번 도니까, 길이가 2000px인 배너는 한 번 이동할 때 2000 / 30 * 60 만큼씩 이동하면 된다고 생각을 하면 안된다.

이동은 어차피 1px 단위인 픽셀 단위로만 이동하며, 계산된 이동 값이 소수점 단위라고 해도 결국에는 픽셀 단위 정수 값으로 표시되게 된다.

 

계산 값이 1.11111111 이 된다고 해서 1.11111111 픽셀씩 이동하는 게 아니며 1픽셀씩 이동하다 어느 시점에는 반올림이 되면서 2픽셀씩 이동하는 중간 프레임이 하나씩 끼어들게 되고, 미세하게 애니메이션이 튀는 느낌적인 느낌이 들게 된다.

 

이 현상을 피하려면 parseInt()로 계산된 결과 값을 정수로 캐스팅을 해서 계산 결과를 명확하게 고정해야 튀는 문제가 생기지 않는다.

 

그리고 실제로 사용하다 보면 1자리 정수 값 범위를 넘는 값을 사용할 일이 없기 때문에 그냥 정수로 값을 명시해서 사용하는 쪽이 더 단순하고 효율적이다.

 

> 두 번째, 조건부로 위치를 리셋하는 if문

애니메이션을 2개의 배너에 적용하지만, 최종적으로는 배너가 왼쪽 바깥으로 완전히 벗어나는 시점에 오른쪽 안 보이는 같은 위치로 옮기는 처리만 하면 되기 때문에 화면 표시 영역 왼쪽 바깥으로 완전히 벗어나는지만 체크하면 된다.

두 배너는 이동 시작 위치는 다르지만 최종적으로는 왼쪽 바깥으로 배너 너비만큼 이동했는지만 알면 된다.

 

 


5.  좌우 페이드 인 아웃 영역 만들기

 

추가로 이동하는 배너 양끝 부분이 부드럽게 보이고 사라지게 만들면 배너가 회전하는 듯한 느낌을 낼 수 있다.

약간은 부가적인 CSS 작업이지만, 배너를 고급스럽게 만드는 간단한 기법이다.

배너를 표시하는 뷰포트 영역 왼쪽과 오른쪽 끝이 자연스럽게 흘러가는 배너가 페이드인/아웃이 되도록 CSS를 만든다.

 

 

과거에는 반투명 PNG 이미지를 좌우에 붙여서 이런 효과를 만들기도 했지만, 지금은 CSS 가상 요소만으로도 구현이 가능하다.

 

흘러가는 배너를 감싸는 요소인 ".group-rolling"에 가상 요소 ::before, "::after" 를 이용해 배너를 감싸는 요소 좌우 끝 부분에 반투명 요소를 붙여 넣는다.

 

.wrap::before{
    content:'';
    position: absolute;
    top: 0;
    left: 0;
    width: 20px;
    height: 100%;
    z-index: 1;
    background: linear-gradient(to right, rgba(170,0,0,1) 0%, rgba(170,0,0,0.75) 51%, rgba(170,0,0,0) 100%);
}
.wrap::after{
    content:'';
    position: absolute;
    top: 0;
    right: 0;
    width: 20px;
    height: 100%;
    z-index: 1;
    background: linear-gradient(to right, rgba(170,0,0,0) 0%, rgba(170,0,0,0.75) 51%, rgba(170,0,0,1) 100%);
}

 

예제에서는 "#a00", 또는 rgb(170,0,0) 컬러(어두운 빨강)를 사용했다.

이 컬러에 투명도를 부여(rgba())해서 불투명 빨강에서 완전 투명한 컬러 사이의 그라데이션을 만들면 된다.

 

좌우에 붙여진 반투명 그라데이션

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.