끊김없이 무한으로 흐르는 텍스트 애니메이션
간단하게 배너 역할을 할 wrap과 그 안에 흘러갈 텍스트를 만들어준다.
html은 2가지 형태로 나누어 해볼 예정인데,
먼저 1. text를 JS로 넣어줄 때
<div class="wrap">
<p class="txt"></p>
</div>
text 부분은 비어주고 마크업한다.
.wrap{
display: flex;
width: 104vw;
position: relative;
left: -2vw;
background: url(./Screen.gif) #fff 50% 50%;
background-size: auto 100%;
margin-top: 10rem;
padding-top: 8rem;
transform: rotate(-5deg);
}
.txt{
display: flex;
padding: 3rem 0;
font-size: 5rem;
white-space: nowrap;
color: purple;
mix-blend-mode: multiply;
}
const wrapTag = document.querySelector('.wrap');
const txtTag = document.querySelector('.txt'),
txt = 'Hello I made a flowing text animation'.split(' ');
우선 태그를 변수에 담아주고,
텍스트를 띄어쓰기 기준 단어별로 잘라내어 txt라는 변수에 담는다.
split('') : 한글자씩 자름
split(' ') : 공백 기준 단어별로 자름
txt.push(...txt)
for(let i=0; i < txt.length; i++){
txtTag.innerText += `${txt[i]}\u00A0\u00A0`
}
같은 txt를 다시 txt에 담아주고,
단어로 조각나있는 문장 2개를 p태그에 한 단어씩 순서대로 넣어준다!
(유니코드 \u00A0 : 띄어쓰기(공백) 사용하여 단어 사이의 여백주기)
그럼 text 준비는 끝나고 이제 움직임을 줘보자!
let xVal = 0;
우선 얼마나 이동될지 이동크기를 담을 변수 : xVal를 만들어둔다. 그럼 이 xVal 값에 따라 text가 이동하게끔 코드를 짜주면 된다.
if(xVal > txtTag.scrollWidth / 2){
txtTag.style.transform = 'translateX(0)'
xVal = 0
}
txtTag.style.transform = `translateX(${xVal}px)`
만약 xVal 값이 txtTag 너비 / 2, 즉 문장 하나의 길이 보다 커지면 txtTag 위치를 0으로 돌리고, xVal 값이 0이 되게 한다.
xVal 값이 작다면 txtTag 위치를 xVal 값만큼 x축으로 이동되게 해준다.
이걸 xVal값이 달라질 때마다 반복하게 해주기위해
function marqueeTxt(xVal, el, dir){
if(xVal > el.scrollWidth / 2){
el.style.transform = 'translateX(0)'
xVal = 0
}
el.style.transform = `translateX(${xVal * dir}px)`
return xVal
}
일단 함수로 담아준다.
function animate(){
xVal+=2
xVal = marqueeTxt(xVal, txtTag, -1)
requestAnimationFrame(animate)
}
animate()
재귀함수 를 이용해 계속 무한실행되도록 해주고,
실행될 때마다 xVal 값이 2(원하는 크기)만큼 증가하게 해준다.
그리고 만들어둔 marqueeTxt 불러와 xVal 값에 넣어주면 끝이다.
(왼쪽으로 흐르게하고 싶어서 방향은 -1로, 오른쪽으로 흐르고 싶다면 1)
〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️
2. text가 태그 안에 있을 때도 코드는 비슷하다.
<div class="wrap">
<div class="txt">
<p>Hello I made a flowing text animation</p>
<p aria-hidden="true">Hello I made a flowing text animation</p>
</div>
</div>
✨사실 접근성을 생각하면 문장이 한 번 읽히도록 하는게 좋기때문에 이 방법을 선호한다.
aria-hidden="true"를 사용하면 리더기가 읽지 않는다.
CSS는 살짝만 수정해주면 되고, JS는 txt빼고 똑같다.
const wrapTag = document.querySelector('.wrap');
const txtTag = document.querySelector('.txt'),
let xVal = 0;
function marqueeTxt(xVal, el, direction){
if(xVal > el.scrollWidth / 2){
el.style.transform = 'translateX(0)'
xVal = 0
}
el.style.transform = `translateX(${xVal * direction}px)`
return xVal
}
function animate(){
xVal+=2
xVal = marqueeTxt(xVal, txtTag, -1)
requestAnimationFrame(animate)
}
animate()
이런식으로 버튼을 이용해 흐르는 방향을 바꿔주고, 누르고 있으면 빠르게 흘러가도록 할 수도 있다.