1. 시나리오
타임라인 리스트를 구현해야 합니다. 왼쪽에는 일련의 작은 점들이 있고 오른쪽에는 리스트 콘텐츠가 있으며, 작은 점의 위치가 리스트 항목과 일치해야 합니다. 최종 결과는 다음과 같습니다:
[caption id="attachment_1220" align="alignnone" width="313"]
타임라인[/caption]
2. 구현 방안
몇 가지 세부 사항이 있습니다:
-
작은 점은 리스트 항목과 정렬되어야 합니다.
-
첫 번째와 마지막 항목의 타임라인은 작은 점을 벗어나면 안 됩니다.
-
리스트 항목 사이에 간격이 있어야 합니다.
처음 두 가지는 자동 조절(Adaptive)에 대한 요구 사항이고, 마지막은 레이아웃에 대한 제한 사항입니다.
전통적인 방식은 리스트 컨테이너를 통해 충분히 긴 세로선을 생성한 다음, 리스트 항목에 작은 점을 달아 세로선에 맞추는 것입니다. 하지만 세로선의 길이를 (JS 계산 없이) 정밀하게 제어할 수 없어 두 번째 조건을 만족하기 어렵습니다. 그래서 방식을 바꿔 리스트 항목이 동일한 높이의 세로선을 직접 가지게 하여 완전한 타임라인으로 이어 붙이도록 합니다.
P.S. 이어 붙인 세로선이 눈에 띌까 봐 걱정하지 마세요. 반드시 완벽하게 이어집니다. 그렇지 않으면 브라우저가 비논리적인 것입니다 (인접한 두 블록 레벨 요소 사이에 설명할 수 없는 틈이 있을 리 없으니, 그들의 border-left는 반드시 완벽하게 연결될 것입니다).
3. 구체적인 구현
먼저 구조를 정합니다. 리스트 항목 간격 제한 때문에 리스트 항목을 한 겹 더 감싸야 합니다:
.listItem>.listItemContent>.listItemContent-date+.listItemContent-content
margin으로 간격을 구현하면 세로선 길이가 맞지 않아 이어지지 않으므로, listItem으로 한 겹 더 감싸고 margin을 padding으로 바꿉니다. listItem이 세로선과 작은 점을 가집니다:
/* 리스트 항목 간격 padding-top */
.listItem {
position: relative;
padding-left: 40px;
padding-top: 4px;
}
/* 리스트 항목 자체 세로선 */
.listItem:before {
content: "";
display: inline-block;
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 100%;
border-right: 1px solid #f3f3f3;
left: 19px;
z-index: 1;
}
/* 리스트 항목 자체 작은 점 */
.listItem:after {
content: "";
display: inline-block;
position: absolute;
width: 8px;
height: 8px;
background-color: #e0e0e0;
border-radius: 4px;
left: 16px;
top: 50%;
margin-top: -2px;
z-index: 1;
}
주의할 점은 작은 점의 margin-top입니다. 이 -2px는 눈대중이 아니라 리스트 항목 간격과 작은 점의 높이와 관련이 있습니다:
// top 50%, marginTop -50%는 작은 점이 listItem에 대해 수직 중앙 정렬됨을 의미합니다.
h = listItemContent.height
pt = listItem.paddingTop
ch = 작은점.height
y = (h + pt)/2 - ch/2
// 우리가 원하는 것은 작은 점이 listItemContent에 대해 수직 중앙 정렬되는 것입니다.
// pt로 인한 하단 오프셋을 제거해야 합니다. offsetY = pt/2
top 50%, marginTop -ch/2 + offsetY
top 50%, marginTop -4 + 2
top 50%, marginTop -2
이는 margin을 padding으로 바꾸고 한 겹 더 감싸면서 생긴 번거로움입니다.
그다음 첫 번째와 마지막 항목의 타임라인이 작은 점을 벗어나지 않도록 제한을 둡니다:
.listItem-first:before {
height: 50%;
top: 50%;
}
.listItem-last:before {
height: 50%;
}
마지막으로 하이라이트 효과를 추가합니다:
/* 하이라이트 작은 점 */
.listItem.highlight:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 16px;
height: 16px;
background-color: #3d93fd;
border: 4px solid #88bdfe;
border-radius: 8px;
left: 12px;
-webkit-box-shadow: 0 0 0 3px #d8e9ff;
box-shadow: 0 0 0 3px #d8e9ff;
z-index: 2;
}
/* 하이라이트 리스트 항목 */
.listItem.highlight > .listItemContent {
background-color: #3d93fd;
color: #fff;
}
/* 하이라이트 리스트 항목 내용 */
.listItem.highlight .listItemContent-date{
color: #fff;
}
4. Demo
온라인 데모: http://www.ayqy.net/temp/timeline/index.html
리스트 항목을 클릭하면 하이라이트되며, 리스트 항목 내용은 HTML과 이미지 크기에 따라 자동으로 조절됩니다.
마치며
최근 JS 애니메이션 원리를 공부하고 있는데, YueYing 선배님의 공유에 감사드립니다. 내공이 정말 깊으시네요.
이전에도 몇 번 보았지만 완전히 이해하지 못했었는데, 직접 구현해 보고 나서야 수학 공식과 easing 연산자의 관계를 깨달았습니다.
강력 추천: 애니메이션에 관해 알아야 할 것들
아직 댓글이 없습니다