Advertisement
  1. Web Design
  2. UI Design
Webdesign

CSS와 JavaScript를 사용해 수평방향 타임라인 만들기

by
Difficulty:IntermediateLength:LongLanguages:

Korean (한국어) translation by Jin Ah Chon (you can also view the original English article)

저는 지난 글에서 기초부터 작성하는 수직방향의 반응형 타임라인을 제작하는 방법을 알려드렸습니다. 오늘은 그와 관련하여 수평방향 타임라인을 만드는 과정을 내용으로 다룰 겁니다.

늘 그렇듯 무엇을 제작할지에 관한 초기 아이디어를 얻도록 관련 CodePen 데모를 보기 바랍니다. (더 나은 경험을 위해 더 큰 버전을 확인해 보세요.)

알려드릴 게 많습니다. 어서 시작해 보죠!

1. HTML 마크업

우리가 수직방향 타임라인에서 정의했던 마크업과 동일하지만, 세 가지 작은 차이가 있습니다.

  • 순서없는 목록(ul) 대신에 순서있는 목록(ol)을 사용합니다. 시맨틱한 면에서 더 정확합니다.
  • 내용이 없는 추가 항목(마지막 항목)이 있습니다. 다음에 올 섹션에서 그 이유를 얘기하겠습니다.
  • 추가 요소(예로 .arrows)가 있습니다. 이는 타임라인 내비게이션을 맡을 겁니다.

다음은 필요로 하는 마크업입니다.

맨 처음에 타임라인은 아래처럼 보입니다.

2. 초기 CSS 스타일 추가하기

단순하게 하기 위해 저는 여기에서 몇몇 기본 폰트 스타일, 컬러 스타일 등을 생략하고 그다음으로 올 구조적인 CSS 규칙을 명시하겠습니다.

여기서 중요한 것은 여러분이 두 가지 사항를 주목하는 것입니다.

  • 목록에 큰 값의 상하 패딩을 줍니다. 한 번 더 말하지만 그 이유를 다음 섹션에서 설명하겠습니다.
  • 여러분이 다음 데모에서 알게 될 것이고 목록이 width: 100vw와 부모 요소에 overflow-x: hidden이 적용되어 있기 때문에 이 시점에서는 항목 전체를 보지 못합니다. 이렇게 하면 항목을 효과적으로 "가리게" 됩니다. 하지만 타임라인 내비게이션 덕분에 나중에는 항목을 두루두루 살펴볼 수 있지요.

적절히 작성한 규칙을 적용한  (실제 콘텐츠 없이 깔끔하게 정렬된) 현 상태의 타임라인은 다음과 같습니다.

3. 타임라인 요소 스타일

이 시점에 우리는 div 요소(지금부터 이 요소를 "타임라인 요소"로 부르겠습니다)에 스타일을 적용할 겁니다. 이 요소는 부분적으로 항목일 뿐만 아니라 가상 요소(pseudo-elements) :: before 를 갖고 있습니다.

더불어 홀수와 짝수 div를 구별시키기 위해 :nth-child(odd):nth-child(even) CSS 가상 클래스를 사용하겠습니다.

다음은 타임라인 요소에 적용할 공통 스타일입니다.

그리고 나서 홀수에 관한 스타일을 적습니다.

그리고 마지막으로 짝수에 관한 스타일을 적습니다.

다음은 콘텐츠가 추가된 새로운 상태의 타임라인입니다.

여러분이 이미 알아챘듯이 타임라인 요소들의 위치가 절댓값으로 정해져 있습니다. 일반적인 문서상의 흐름과 관련이 없다는 의미이지요. 이 의미를 염두해 두고, 타임라인 전체가 보이도록 목록의 상하 패딩 값을 크게 잡아 주세요. 패딩 값을 적용하지 않는다면, 아래처럼 타임라인이 잘려 보일 겁니다.

How the timeline looks like without paddings

4. 타임라인 내비게이션 스타일

내비게이션 버튼에 스타일을 적용할 시간이네요. 기본적으로 이전 버튼에 disabled 클래스를 주어 이전 버튼을 비활성화시킨다는 것을 기억하세요.

그에 관한 CSS 스타일은 다음과 같습니다.

위의 규칙을 적용하면 타임라인은 이와 같이 됩니다.

5. 인터랙션 추가하기

타임라임의 기본 구조가 준비되었네요. 거기에 인터랙션을 추가해 보죠!

변수

맨 먼저 해야 할 작업은 이후에 사용할 변수들을 설정하는 것입니다.

초기화

모든 페이지의 에셋(assets)이 갖추어 졌을 때 init 함수를 호출합니다.

이 함수는 4개의 하위 함수를 동작시킵니다.

순식간에 보게 되겠지만, 각각의 함수는 특정한 작업을 완수합니다.

높이가 동일한 타임라인 요소들

마지막 데모로 돌아가보면 타임라인 요소가 동일한 높이를 갖지 않는다는 사실을 알게 될 겁니다. 타임라인의 주요 기능에 영향을 미치지는 않더라도 모든 요소의 높이가 동일한 것을 선호할 듯 싶습니다. 그렇게 하기 위해서는 CSS에서 높이를 고정시키던지(쉬운 해결 방법) 자바스크립트에서 가장 높은 요소의 높이에 대응하도록 높이를 동적으로 적용하게 할 수 있습니다.

두 번째 선택이 좀 더 융통성 있고 안정적입니다. 자, 다음은 그 동작을 실행하는 함수입니다.

이 함수는 가장 높은 타임라인 요소의 높이를 가져와 모든 요소의 기본 높이로 설정해 줍니다.

적용된 타임라인은 다음과 같이 보입니다.

6. 타임라인 움직이기

이제는 타임라인 애니메이션에 집중해 보죠. 이 동작을 실행하는 함수를 순차적으로 작성해 볼 겁니다.

먼저 타임라인 버튼에 클릭 이벤트 리스너를 등록합니다.

버튼 하나가 클릭될 때마다 타임라인 버튼의 비활성화 상태를 체크합니다. 만일 버튼이 비활성화 되지 않았다면 비활성화 시킵니다. 이로써 양쪽 버튼은 애니메이션이 끝날 때까지 단 한 번만 클릭되게 됩니다.

그래서 코드를 보면 클릭 핸들러는 처음 아래와 같이 작성됩니다.

다음과 같이 다음 단계들을 진행합니다.

  • 버튼을 클릭했던 게 처음인지 확인해 봅니다. 한 번 더 얘기하지만, 이전 버튼은 기본적으로 비활성화되어 있다는 점을 유념하세요. 그러기에 처음에 클릭할 수 있는 유일한 버튼은 다음 버튼입니다.
  • 만약에 처음인 경우라면 transform 속성을 써서 타임라인을 오른쪽으로 280px 이동할 겁니다. xScrolling 변수의 값이 이동할 양을 결정하지요.
  • 오히려 반대로 버튼을 이미 클릭했었다면, 우리는 타임라인의 현재 transform 값을 가져와서 그 값에 이상적인 이동 분량(예로 280px)을 더하거나 뺄 겁니다. 그러니까 이전 버튼을 클릭하는 한 transform 속성 값은 감소하고 타임라인은 왼쪽에서 오른쪽으로 이동하게 됩니다. 그러나 다음 버튼을 클릭했을 때 transform 속성 값은 증가하며, 타임라인은 오른쪽에서부터 왼쪽으로 이동하게 되는 거죠.

이 기능을 실행하는 코드는 다음과 같습니다.

훌륭해요! 타임라인을 이동시키는 방식을 금새 작성했습니다. 그다음으로 넘어야 할 산은 언제 애니메이션을 정지해야 하는지를 파악하는 것입니다. 그 접근 방식은 다음과 같습니다.

  • 타임라인의 첫 번째 요소가 전부 보여질 때는 타임라인이 이미 시작점에 놓여 있다는 의미입니다. 그러므로 이전 버튼을 비활성화시킵니다. 또한 다음 버튼은 활성화시킵니다.
  • 타임라인의 마지막 요소가 전부 보여질 때는 타임라인이 이미 마지막 지점에 놓여 있다는 말이지요. 고로 다음 버튼을 비활성화시킵니다. 그와 더불어 이전 버튼을 활성화시킵니다.

마지막 요소는 타임라인 요소의 너비(예, 280px)와 같은 너비이며 비어 있다는 점을 기억하세요. 그 값(이나 더 큰 값)을 준 이유는 다음 버튼이 비활성화 되기 전에 마지막 타임라인 요소가 먼저 보여지길 바랐기 때문입니다.

타겟 요소가 현재 뷰포트에서 전부 보여지는지 아닌지를 감지하기 위해 우리는 수직방향 타임라인에서 썼던 코드를 똑같이 활용할 겁니다. 출처가 Stack Overflow 스레드이고 작성될 코드는 다음과 같습니다.

위의 함수 외에 또다른 헬퍼를 정의해 줍니다.

이 함수는 flag 매개 변수의 값에 따라 요소에서 disabled 클래스를 붙였다 떼었다 합니다. 그와 함께 이 요소의 비활성화 상태를 변경해 줄 수 있습니다.

위의 작성된 코드를 기반으로 하여 애니메이션이 정지하거나 계속되어야 하는지에 관해 체크하는 코드는 다음과 같습니다.

이 코드를 실행하기 전에 1.1초 지연 시간이 있다는 점을 주목해 주세요. 왜 이렇게 할까요?

CSS로 되돌아 가보면 아래의 규칙이 보일 겁니다.

그러니까 타임라인 애니메이션에서 완료되기 까지 1초가 필요합니다. 애니메이션이 끝나고 100 밀리세컨드를 기다리죠. 그런 다음 상태 체크를 수행합니다.

애니메이션이 적용된 타임라인이 여기 있습니다.

7. 스와이프 지원하기

지금까지 타임라인은 터치 이벤트에 반응하지 않습니다. 그 기능을 추가한다면 더할 나위 없이 좋겠지요. 그 기능을 구현하려면 자체적으로 실행되는 자바스크립트를 작성하거나 외부에 있는 연관된 라이브러리(예, Hammer.jsTouchSwipe.js) 중에 하나를 쓰면 됩니다. 

이 글의 데모 용으로 Hammer.js를 써서 단순함을 유지하겠습니다. 자, 먼저 이 라이브러리를 펜(pen)에서 inlcude 합니다.

How to include Hammerjs in our pen

그런 다음에 관련 함수를 명시합니다.

위에 명시한 함수 안에 아래의 내용을 적용합니다.

  • Hammer의 인스턴스를 생성합니다.
  • swipeleftswiperight 이벤트용 핸들러를 등록합니다.
  • 우리가 타임라인을 왼쪽 방향으로 스와이프할 때, 다음 버튼에 클릭 함수를 실행하여 타임라인이 오른쪽에서 왼쪽으로 이동하게 합니다.
  • 타임라인을 오른쪽 방향으로 스와이프할 때는 이전 버튼에 클릭 함수를 발생시켜 타임라인이 왼쪽에서 오른쪽으로 이동하게 합니다.

스와이프가 지원되는 타임라인 입니다.

키보드 내비게이션 추가하기

키보드 내비게이션을 지원함으로써 사용자 경험에 한층 더 나아가도록 합시다. 목표는 다음과 같습니다.

  • 왼쪽이나 오른쪽 화살표 키가 눌렸을 때 (페이지에서 다른 섹션이 현재 보인다면) 화면(document)이 타임라인의 상단으로 스크롤될 것입니다. 이렇게 하면 타임라인의 전체가 보여지게 되지요.
  • 특히 왼쪽 화살표 키가 눌리면 타임라인은 왼쪽에서 오른쪽으로 이동해야 합니다.
  • 동일한 방식으로 오른쪽 화살표 키가 눌리면 타임라인은 오른쪽에서 왼쪽으로 이동해야 합니다.

그에 관한 함수는 다음과 같습니다.

키보드 기능이 적용된 타임라인입니다.

8. 반응형으로 제작

얼마 남지 않았어요!  마지막으로 타임라인을 반응형으로 만들어 봅시다. 뷰포트가 600px 이하일 때 다음과 같이 순차적으로 정렬된 레이아웃이 되어야 합니다.

데스크톱을 우선으로 한 접근법을 사용했으므로 다음과 같이 CSS 규칙을 적용해 덮어쓰기 되도록 합니다.

중요: 위에 적힌 규칙 중에서 두 가지는 자바스크립트에서 적용된 인라인 스타일을 덮어쓰도록 하기 위해 !important를 사용해야 했습니다. 

타임라인의 최종 상태입니다.

브라우저 지원

이 데모는 최신 브라우저와 기기에서 잘 동작합니다. 또한 여러분이 아마 알고계실 테지만, 우리는 ES6 코드를 ES5로 컴파일하는 데 Babel을 활용했습니다.

타임라인을 테스트하는 중에 맞닥뜨렸던 유일한 작은 이슈는 타임라인이 이동하는 중에 발생하는 텍스트 렌더링 변화입니다. 다른 Stack Overflow 스레드에서 제시된 다양한 방법을 시도했으나 모든 종류의 OS와 브라우저에 대한 간단한 해결책을 찾지 못했습니다. 그래서 타임라인의 이동 중에 작은 폰트 렌더링 이슈를 여러분이 보게 될 수도 있다는 점을 유의하시기 바랍니다.

마무리

꽤 상당한 분량인 이 튜토리얼에서 우리는 심플한 순서 있는 목록(ol)으로 시작해서 수평방향 반응형 타임라인을 제작했습니다. 확실히 다수의 흥미로운 내용을 다루었지요. 최종 결과가 나오기까지 작업했던 과정을 즐기셨길 바랍니다. 그리고 여러분이 새로운 지식을 쌓는 데 도움이 되었으면 합니다.

질문이 있거나 이해가 되지 않는 부분이 있었다면 바로 아래에 있는 댓글에 적어서 제게 알려주세요!

다음 단계

이 타임라인을 더 향상하거나 확장시키고 싶다면, 여러분은 다음과 같은 작업을 할 수 있습니다.

  • 드레그 기능 추가하기. 내비게이션 용도로 타임라인 버튼을 클릭하는 대신 타임라인 영역을 간단히 드래그할 수 있습니다. 이 동작을 실행하기 위해서 여러분은 내이티브 Drag and Drop Api (안타깝게도 이 글을 작성하는 시기에 모바일 기기를 지원하지 않습니다) 혹은 Draggable.js와 같은 외부 라이브러리를 사용하면 됩니다.
  • 브라우저의 창크기 변경 시 타임라인의 동작을 개선하기. 가령 창크기를 달리했을 때 그에 맞춰 버튼이 비활성화 되고, 활성화 되도록 합니다.
  • 관리를 잘 할 수 있는 방식으로 코드를 구조화하기. 일반적인 자바스크립트 디자인 패턴을 사용해 보세요.
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.