본문으로 건너뛰기

순수 CSS 타임라인 리스트

무료2016-11-19#CSS#css时间轴#移动端时间轴#自适应时间轴#时间轴效果#timeline pure css

콘텐츠 크기에 맞춰 자동 조절되는 타임라인 리스트

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으로 한 겹 더 감싸고 marginpadding으로 바꿉니다. 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

이는 marginpadding으로 바꾸고 한 겹 더 감싸면서 생긴 번거로움입니다.

그다음 첫 번째와 마지막 항목의 타임라인이 작은 점을 벗어나지 않도록 제한을 둡니다:

.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 연산자의 관계를 깨달았습니다.

강력 추천: 애니메이션에 관해 알아야 할 것들

댓글

아직 댓글이 없습니다

댓글 작성