앞서 글에서 소개한 Snappy의 프리랜딩 페이지를 만들었는데, 이번 작업에서 사용한 각종 라이브러리와 그 과정에서 얻은 노하우를 공유한다. 이전 글이랑 비교하여 말이 짧아졌다고 당황하지 말도록. 사실 오늘 새벽에 이 글을 먼저 쓰고 아까 글을 나중에 쓴거라 미처 신경쓰지 못했다. 


메이 따꺼 쎤머 라우 뿌이 허 (대인배들은 이런걸 신경쓰지 않는다.)

씌엔 쓰 르 커우 칭따오 까이 르 (내 블로그 팬들은 소중하니까)



스크린샷 한장 한장 찍어 설명하면서 넘어가보자.



- 첫번째 섹션

보라색 바탕에 각종 쇼핑몰 로고가 있고, 마우스 움직임에 따라 배경이 움직인다.

깊이감을 주고, 패럴렉스한 효과를 내기 위해 각종 쇼핑몰 로고가 점점이 박힌 투명 png 파일 세장을 겹쳤다. 세장 각각 가속도를 다르게 하여 마우스 움직임에 따라 움직임에 차이가 나게 했다. 모바일에서 볼 때는 휴대폰의 기울기에 따라 움직임이 발생하는데 느낌이 꽤 좋은 편.(원래 안좋았는데 라이브러리 바꾸니 좋아졌다..)


사용 라이브러리는 parallax.js 인데, 이 사용 용도에서는 완벽한 것 같다. 패럴렉스 효과는 일반적으로 2가지로 나눌 수 있는데, 요새 유행처럼 다들 쓰는, 스크롤 할 때 배경이 고정되어 닦여 올라가는(?) 느낌이 들게 하는게 있고, 또 하나는 이렇게 마우스를 움직이거나 디바이스를 흔들면 시차 효과를 주는게 있다.


궁금하면 마우스를 움직여보자.


처음에 사용한 라이브러리는 interactive_bg.js 인데, 배경을 확대하고 움직이는 정도의 기능만 하는지라 스크롤이 스무스하지 않고 버벅이는 느낌이 들었다. 그래서 모바일에선 3장 중 2장을 가려서 한장만 움직이게 하는 등의 삽질을 했는데.. 라이브러리를 parallax.js로 바꾸고 완전 해결. 정말 적용도 간단하고.. 문서도 이정도면 훌륭하다. 다만 스크립트를 페이지 맨 마지막에 불러와야 제대로 작동하고, 페이지 처음에 불러올 경우 body에서 스크롤이 안되는(!) 골때리는 문제가 있다. 다른 라이브러리랑 충돌이 난건지, 어디엔가 position 설정이 잘못 되었는지 골머리 앓고 라이브러리 까서 한줄씩 지우면서 찾아보다가 범인을 알아내고 허탈해짐. 여튼 이 라이브러리는 가속도 적용이나 애니메이션의 easing 등이 완벽해서.. 아 정말 써보면서 눈물나는줄. 완전 강추.


하단의 쇼핑몰 스샷이 좌측으로 무한 슬라이드 되는 효과는 slick.js를 사용했다. 캐로셀 효과 넣는데는 slick.js 만큼 깔끔한게 없는것 같다. 예제도 잘 정리되어 있고, 문서도 무척 깔끔하다. 왠만한건 이놈이 다 커버하는듯.





- 두번째 섹션

보라색 바탕에 우측에 휴대폰 잡고 있는 손이 보인다. 스크롤을 하면 휴대폰 안의 화면이 스크롤된다.

원래 배경이랑 손이랑 통짜로 JPG 파일 붙인 다음, 그 위에 휴대폰 스크린샷만 슬라이드 시키고 싶었는데, 잘 보면 손가락들이 스크린샷을 침범하고 있다. 그래서 PNG로 저장했더니 파일 용량이 어마어마하게 크더라. 그래서 이미지를 좌 / 우 / 위 / 아래로 썰어서 JPG로 저장하고, 침범하고 있는 손가락 부분만 투명 PNG로 바꾸어 용량 부분 해결. 근데 지금 보니까 그냥 전체를 JPG로 깔아버린 다음, 손가락 부분만 PNG로 해서 절대값으로 띄워주면 되지 않냐는 생각이 든다. 그럼 이미지 썰지 않아도 되는데 아오..


이 부분은 원래 패럴렉스 효과를 넣어서, 화면을 스크롤함에 따라 휴대폰의 쇼핑몰 리스트가 위아래로 움직이는 효과를 주고 싶었다. 스크롤을 아래로 하면 화면은 위로 움직이는 식.. 하지만 패럴렉스 관련 라이브러리들이 적용이 워낙 복잡하고 힘들더라. 특히 stellar.js는 최악중 최악인데, 예제도 빈약하고 문서도 개판이다. 그 와중에 첫화면에서는 easy 라고 적어놨는데 엄청 열받더라구. 들어가자 마자 가로스크롤인건 생각도 못하고 이게 뭥미.. 했건만.. 개발자 스스로는 무척 쉽다고 생각하는 모양인데, 아 착각좀 그만.. 아무튼 종종 만나는, 문서나 샘플이 거지같은 라이브러리중 하나다.


여튼 패럴렉스 갖고 씨름하다가, 그냥 scrollMonitor.js 로 스크롤 하다가 화면이 뷰포트에 다 들어오면 자동으로 스크롤을 작동시키는 간단한 방식으로 수정했다. 스크롤 모니터도 강추 라이브러리인데, 원하는 레이어에 스크롤모니터를 걸고 화면 안에 들어오면 이러이러한 펑션을 수행한다- 정도로 적으면 끝. 완전 훌륭하다.





- 세번째 섹션

30여개의 쇼핑몰 로고가 화면 주변에서 안쪽으로 스르륵 모이는 효과가 메인. 이놈 역시 scrollMonitor로 트리거. 정말 피곤한건 30여개의 로고들을 일일히 다 좌표를 따서 애니메이션 시작 전과 후를 각각 top, left를 지정해야 한다는 점이다. 처음에는 화면 중앙을 기준으로 잡을라고 했는데, 도무지 승산이 없어서 둘러싸는 고정 크기 사각형의 레이어 안에서 좌표를 잡고, 그 레이어를 중앙으로 정렬하는 식으로 바꾸었다. 지금 와서 생각해보니 그렇게 하나 저렇게 하나 다 똑같은데 왜 고생을 했는지 모르겠다.



소스는 대략 위와 같다. 좌표값 보면 개고생의 냄새가 난다. SCSS에서 each 어떻게 돌리고 문자열 안에서 어떻게 적용하는지 어려워하는 경우가 있는데, 위를 참고하면 별로 어렵지 않음을 알 수 있다.


으 아무튼 '로고들이 모인 상태'들을 죄다 따서 좌표를 찍은다음, 그걸 엑셀에 집어넣고 각각 얼마얼마씩 움직인 값을 밑에 한번 더 적어준 다음 ease-out으로 적당히 transition 찍어주면 애니메이션은 끝난다. 분노의 숫자 노가다 해놓고 실행시켜봤더니 효과가 은근히 근사해서 만족하는 중.


이 섹션에서는 퍼포먼스 관련 큰 이슈가 있었는데.. 내가 원래는 저 로고들을 CSS 에서 백그라운드로 까는게 아니라 HTML상에서 이미지 태그로 불러왔다. 그랬더니 필연적으로 웹 브라우저는 CSS보다 먼저 로딩된 HTML에서 언급된 이미지를 먼저 로딩하게 된다. 그러니까.. 사용자가 웹 페이지를 호출하면, HTML이 먼저 날아오고, 거기 언급된 CSS와 이미지를 로딩하고, CSS를 로딩하면 그 안에 언급된 이미지나 웹폰트를 불러오는 식이다. 그 과정에서 CSS에서 언급된 이미지들이 가장 나중에 로딩되는 문제가 발생한다. 그리고 그 가장 나중에 로딩될 이미지가 하필이면 맨 첫번째 섹션의 큼직한 투명 배경 이미지 3장들이다. 저 30개의 쇼핑몰 로고를 전~부 불러올 때 까지 맨 첫 화면의 배경이미지가 로딩되지 않는 참사가 벌어지는 것이다.


HTTP 요청으로 동시에 불러올 수 있는 파일 수는 8개니까, 30개 쇼핑몰 불러오는 동안 한 4번의 사이클이 지나게 되고, 그 최소 3초가 넘는 시간동안 페이지는 텅 비어있거나 버벅거리거나 계단식으로 로딩되는 큰 문제가 발생하는 것이다. 이등병들 급식 받는데 줄 저 맨 뒤에 쓰리스타가 식판 들고 서 있는 느낌이랄까.. 혹은 응급실에 가득찬 감기와 무좀 환자 때문에 진짜 응급환자의 차례가 늦게 돌아오는 느낌이랄까..


그래서 나는 맨 처음 로딩되어야 할 이미지들을 일단 가로세로 0픽셀에 visiblity: hidden 으로 처리한 레이어 속에 미리 로딩시켰다. (display: none은 안된다. 브라우저에서 display: block 등이 되기 전에는 아예 로딩 안시키기 때문. ) 이걸로 일단 이미지 로딩 우선순위는 해결 되었다.


그 다음으로 해결할건 30개의 쇼핑몰 이미지가 갖고오는 HTTP 요청 부하 해결이다. 이건 그냥 스프라이트로 처리하면 끝이다. 30개의 이미지들을 1개의 이미지로 바둑판식으로 붙인 다음, 가로세로 사이즈가 고정된 레이어 안에서 overflow: hidden으로 제한 한 다음 background-position으로 움직여주면 한 이미지를 여러 이미지 처럼 사용할 수 있다. 레일즈에서 compass 이용하면 간편하게 게임 끝. 위 소스를 보면 알다시피 이미지 가로세로도 알아서 계산해주므로 할게 거의 없다. 스프라이팅 덕분에 HTTP 요청 숫자도 줄어들고, 이미지 가로세로 사이즈 계산할 필요도 없어졌다. 거기다가 HTML에서 직접 이미지를 언급하는게 아니라 CSS에서 백그라운드로 깔기 때문에 우선순위 문제도 해결.





- 원카트 시뮬레이션 섹션

이거야 말로 노가다의 결정체인데 -_-;; 실제 앱 사용 모습을 웹에서 좀 맛보기로 보여주기 위해서 삽질이 필요했다. 일단 처음에는 동영상으로 구현을 하고 싶었다. 아이폰을 맥에 USB로 연결한 다음, 퀵타임에서 녹화를 하면 앱 사용하는 모습이 그대로 동영상이 된다. 어썸. 근데 문제는 이 경우 터치 할 때 어디를 터치했는지 보이지를 않는다는게 문제가 되었다. 뭐 동영상을 촬영한 다음 후처리를 통해서 터치 인디케이터를 집어넣으면 되지만.. 그것은 또다른 범주의 노가다가 된다. 게다가 앱이 아직 덜 완성된지라 디자인이 계속 바뀌고, 앱도 계속 발전하는 터라 동영상을 넣으면 계속된 반복 노가다가 예상되었다. 그래서 나는 JS/CSS로 모두 때우기로 했다 -_-;;




일단 일련의 스크린샷들 목록을 타이밍에 맞게 보여주고, 가리고, 스크롤시키면서.. 터치 인디케이터 역시 타이밍에 맞게 위로 스크롤하고, 탭 하는 모습을 보여주는 식으로 코딩했다. 위 소스를 보면 알다시피 정말 노가다의 연속이다-_-;; 개발자들은 다들 알다시피 모든 노가다에는 지름길이 있으므로, 혹시 이런 작업들을 쉽게 할 수 있는 방법이 있다면 좀 알려주길 바람. 아 좀 보면서 한심해하지 말고 알려달라고 좀 ㅠㅠ 내가 학창시절에 스프라이팅의 비밀을 모르고 포토샵으로 여러 이미지들을 일일히 기워 만든 다음 좌표 일일히 찍던 것 처럼 이것도 쉬운 길이 있지 않을까.. 싶다.





- 이메일 수집폼

이 페이지에는 가장 중요한 두가지 목적이 있다. 첫째가 스내피라는 앱에 대해 대략적으로 소개하고 기대감을 불러일으키는 것이고, 둘째가 바로 이메일 수집이다. 충분한 양의 이메일이 수집되어야 출시 초기에 트래픽을 끌어와 앱스토어 순위를 끌어올릴 수 있기 때문이다. 아무튼 모달 창을 어떻게 쌔끈하게 보여줘야 사람들이 많이 클릭할지 고민했는데.. 


앱이 일단 iOS용으로 먼저 개발되고, 안드로이드가 다음이므로 앱 출시 시에 플랫폼에 맞는 알림을 보내기 위해서는 사용 OS 데이터가 필요하다. OS 정보를 메일 주소 입력폼 아래의 작은 라디오 버튼 따위로 입력받기보단 이렇게 버튼 하나 누르면 끝나는 식으로 만드는게 사용자 입장에선 좋을듯. 게다가 라디오 버튼의 경우 기본값이 iOS에 걸려 있을 경우 사람들이 귀찮아서 이메일만 집어넣고 보낼 수도 있다. 이때 iOS의 비중이 높아지는 문제가 발생할 수 있음. 위 스샷에선 간단한 스텝을 강제로 하나 넣기 때문에 '기본값'이 없어 데이터를 오류 없이 받아올 수 있어 좋다.


모달 창이 등장할 때 모션 블러가 일어나면서 왼쪽에서 선택지가 튀어나오는데, 이건 Lucas Bebber의 'Motion Blur Effect with SVG'를 참조했다. 데모를 보면 알겠지만, 효과가 엄청나게 쌔끈하다. 하지만 너무 진보된 기술을 사용하고 있기 때문에 특정 브라우저에서만 사용이 가능하고, 특히 사파리에서 작동하지 않는다는 점(;;;)은 매우 치명적이었다. 그래서 나는 진보된 기술을 쓰지 않고 아주 무식한 방법으로 해결했다.




포토샵으로 가로로 모션 블러를 걸어서 저장한 투명 png 파일을 날아오게 하고, 그 다음에 실제 레이어를 보여주는 식의 편법을 썼다. 분명 원래 모션 블러 효과보단 후져 보이지만 그래도 그럴싸하게 동작한다 ㅋㅋ;; 또한 오리지널에 있던 초기 준비 시간이 없어서 쾌적하고 좋다.


궁금하면 직접 해보자. 메일 주소도 적어주고 좀..






- 쇼핑몰 목록

실제 DB와 연동하여 운영중인 쇼핑몰 목록을 태그별로 소팅할 수 있게 했다. 배열하는것 정도라면 그냥 masonry를 사용하면 되지만, 소팅이 들어가야 하기 때문에 isotope를 사용하였다. 거기다가 타일 배열이 큰게 있고 작은게 있는데, 이가 빠지지 않고 예쁘게 들어가야 하므로 packery 레이아웃 모드를 따로 설치하여 사용하였다. 다른 레이아웃 모드를 사용하면 말로 설명하기 어려울만큼 이상하게 나온다. 



또 하나 골때리는 부분은 라운드 처리된 버튼의 표현 문제였다. #디자인과 #키즈를 잘 보라. 키즈 부분이 유달리 윤곽선이 괴랄함을 알 수 있다. 저건 그냥 border-radius: 21px 만 적용한거고, 위에 디자인 부분은 안쪽에 border-radius: 20px짜리 레이어를 하나 더 넣어준거다. 정말 이거 해결하느라 머리털 다 빠지는 줄 알았다. 한시간 정도 고생한것 같은데, 결과물이 만족스러워서 다행. 확대해볼까?

확대하니 별로 티가 안난다 -_-;;; 또 웃기는게 이게 레티나 디스플레이일 경우 역시 티가 나지 않는다. 환장할 노릇..



- 이미지 최적화

사이트를 어느 정도 완성한 다음에는, 크롬 개발자 도구의 네트워크 탭을 열어서 퍼포먼스 테스트를 한다. 여기서 미처 압축하지 못한 가로세로 100px 썸네일 따위가 막 3MB 먹고 이런 문제를 사전에 찾아낼 수 있다.



보면 어떤 과정을 거쳐 페이지가 로딩되는지, 누가 용량을 많이 먹고 시간을 많이 잡아먹는지 알 수 있다.


가장 최적화 하기 좋은건 이미지 갯수와 사이즈다. 아까 30장이 넘는 쇼핑몰 이미지가 가져오는 해악에 대해 이야기 했고, 그것에 대한 대안으로 스프라이팅과 미리 로딩해두는것을 제시했다. 이번에는 이미지 용량 줄이기가 필요한 시점인데..


보통 이미지에는 각종 메타 데이터가 들어있거나 해서 포토샵에서 Save As Web 으로 저장하거나, ImageOptim 등을 돌려서 용량을 줄인다. 하지만 이 경우 이미지 품질에 별 차이가 없는 대신 용량이 아주 미약하게 줄어들어 하나 안하나 큰 차이가 없다.


JPG의 경우 포토샵에서 저장할때 Save As Web을 눌러 이미지 품질 슬라이더를 조절해가며 절충점을 찾는다. 눈에 확 들어오는 이미지의 경우 압축률을 낮게 해서 또렷한 이미지를 보여줘야 한다. 하지만 애니메이션으로 슥슥 지나가거나 배경에 살짝 깔리는 이미지의 경우 압축을 많이 해서 형편없게 보여줘도 눈에 띄지 않기 때문에 최대한 줄여보자.


PNG의 경우 줄이는게 좀 여의치 않은 편인데.. 8bit PNG로 저장할 경우 용량은 아주 작지만 품질이 안좋고 알파 채널을 사용할 수 없다. 반면 PNG 24bit나 32bit 로 저장할 경우 용량이 커지고 알파채널을 사용할 수 있다. 근데 이번에 페이스북에 저 페이지를 공유하고 의견을 받는 과정에서 정보를 얻었는데.. pngquant라는 엄청난게 있더라. PNG를 손실압축(색상 수를 줄인다)으로 용량을 줄이는 방식인데, 써보니까 용량은 거의 원본의 30%대로 줄어드는데 이미지 품질에는 거의 차이가 없어서 놀랬다. 원래 포토샵에서는 PNG 24bit의 경우 색 제한 옵션이 없어 투명도를 사용하려면 울며 겨자먹기로 용량 상승을 감안해야 했다. 하지만 색 제한으로 용량 상승을 억제하면서 투명도를 쓰는게 가능하다! 맥 사용자의 경우 ImageAlpha라는 앱을 사용하면 된다. 쉽게 이미지를 줄여가며 확인하고, 저장 후에 자동으로 ImageOptim으로 연결하여 마무리까지 해준다.


이런 모든 과정의 결과, 페이지 처음 만들었을 때는 10MB가 넘던 로딩 용량이 3MB로 많이 줄어들었다. 게다가 캐시를 끈 상태에서 로딩 끝나는 시점도 2초 내외로 업계 평균이랑 비교해볼때 아주 만족스러운 속도다. 이게 최적화 전에는 10초를 넘어가고 난리도 아니었는데, 이것저것 고치다보니 많이 빨라졌다.


...


휴.. 여태까지 이 랜딩 페이지 하나를 개발하면서 배운것과 사용한것들을 쭈욱 적어봤는데, 누구에겐 밥먹듯이 하는 작업이고 누구에겐 생소한 경험이리라. 이미지 사이즈 30%로 줄이는 법 배운게 가장 큰 소득인듯. 간단한 두페이지짜리 프로젝트지만, 이번거 진행하면서 라이브러리들 활용하는 법 많이 배웠고, DB쿼리 최적화 하는 작업도 조금은 맛봤다. 다음 프로젝트 까지 해내면 슬슬 코드 멍키는 탈출하지 싶다. 


다음 번에는 좀 더 그럴싸한걸로 잘난척 할 수 있길 바라며 글을 끝맺는다.





오비완이 최면을 건다.

1. 이 글을 친구와 동료에게 공유하고 2. 내가 만든 페이지를 살펴보고 3. 이메일 주소도 입력한다.


사실 위의 내용을 수행하면 잘생겨진다. 왜냐 하면 내 팬들은 극도로 높은 확률로 잘생겼기 때문이다. (이건 12년째 이어온 사실이며 누구도 이견을 제시하지 않는다.) 그리고 예쁘고 잘생겨지면 애인이 생길 확률이 높아진다. 연봉도 올라갈 것이다. 날씨 쌀쌀한 연말이고 마침 스타워즈가 개봉하기 때문에 주문의 효과는 배가된다.


혹시 나는 이미 잘생겼는데 왜 여태 연봉이 오르지 않았냐고 물어본다면, 이 글을 공유하지 않았기 때문이라고 자신있게 이야기할 수 있다. 공요롭게도 당신의 연봉이 여태 오르지 않았다는 사실과 내 글을 공유하지 않았다는 사실이 일치하지 않는가! 세상에 소름끼치는 진실이다.


한마디 더 해보자. 내 독자들이 잘생긴 이유가 궁금한가? 내게 남은게 하나도 없을 정도로 팬들에게 잘생김을 나눠주었기 때문이다. 나의 희생정신 앞에 숙연한 마음이 들지 않는다면 당신은 피도 눈물도 없는 사람이다...



https://snappy.global/pre/miriya-blog



사실 너무 오버하긴 했는데 아무튼 의리로 좀 눌러주길. 내가 사주를 봤는데, 2016년에 내 인생이 편데. 그럴라면 이 서비스가 성공해야 해. 그러니까 메일 주소좀 넣어줘. 스팸메일 안보낼게 에이.. 이 사람..