HTML + CSS PlatoBlockchain 데이터 인텔리전스를 사용한 완벽한 목차. 수직 검색. 일체 포함.

HTML + CSS를 사용한 완벽한 목차

올해 초, 나는 JavaScript 약속 이해하기 (무료 다운로드). 인쇄본으로 만들 생각은 없었지만 많은 분들이 인쇄본에 대해 문의해 주셔서 저도 자가출판을 하기로 했습니다. HTML과 CSS를 활용하면 쉽게 연습할 수 있을 거라 생각했습니다. PDF를 생성한 다음 프린터로 보냅니다. 내가 깨닫지 못한 것은 인쇄 책의 중요한 부분인 목차에 대한 답이 없다는 것이었습니다.

목차의 구성

기본적으로 목차는 상당히 간단합니다. 각 줄은 책이나 웹 페이지의 일부를 나타내며 해당 콘텐츠를 찾을 수 있는 위치를 나타냅니다. 일반적으로 라인에는 세 부분이 포함됩니다.

  1. 장 또는 섹션의 제목
  2. 제목과 페이지 번호를 시각적으로 연결하는 지시선(예: 점, 대시 또는 선)
  3. 페이지 번호

목차는 마이크로소프트 워드나 구글 독스 같은 워드 프로세싱 도구 내에서 생성하기 쉽지만, 내 콘텐츠가 마크다운에 있었다가 HTML로 변환되었기 때문에 나에게는 좋은 선택이 아니었다. 나는 인쇄에 적합한 형식으로 목차를 생성하기 위해 HTML과 함께 작동하는 자동화된 것을 원했습니다. 또한 웹 페이지와 PDF에서 문서를 탐색하는 데 사용할 수 있도록 각 행이 링크가 되기를 원했습니다. 나는 또한 제목과 페이지 번호 사이에 점선을 원했습니다.

그래서 연구를 시작했습니다.

HTML과 CSS로 목차를 만드는 방법에 대한 두 개의 훌륭한 블로그 게시물을 발견했습니다. 첫 번째는 "HTML에서 목차 만들기" 줄리 블랑. Julie가 작업한 PagedJS, 인쇄용 문서 형식을 적절하게 지정하는 웹 브라우저의 누락된 페이지 미디어 기능에 대한 폴리필. 나는 Julie의 예부터 시작했지만 그것이 나에게 잘 맞지 않는다는 것을 발견했습니다. 다음으로 크리스토프 그라보의 “CSS를 사용한 반응형 TOC 리더 라인” 정렬을 쉽게 하기 위해 CSS 그리드(Julie의 부동 소수점 기반 접근 방식과 반대)를 사용하는 개념을 도입한 게시물입니다. 그러나 다시 한 번 그의 접근 방식은 내 목적에 맞지 않았습니다.

하지만 이 두 게시물을 읽은 후 레이아웃 문제에 대해 충분히 이해하고 스스로 착수할 수 있다고 느꼈습니다. 두 블로그 게시물의 일부를 사용하고 몇 가지 새로운 HTML 및 CSS 개념을 접근 방식에 추가하여 만족스러운 결과를 도출했습니다.

올바른 마크업 선택

목차에 대한 올바른 마크업을 결정할 때 나는 주로 올바른 의미에 대해 생각했습니다. 기본적으로 목차는 거의 키-값 쌍처럼 페이지 번호에 연결된 제목(장 또는 하위 섹션)에 관한 것입니다. 그로 인해 두 가지 옵션이 생겼습니다.

  • 한 가지 옵션은 테이블(<table>) 제목에 대한 하나의 열과 페이지에 대한 하나의 열이 있습니다.
  • 그런 다음 자주 사용되지 않고 잊혀진 정의 목록(<dl>) 요소. 또한 키-값 맵 역할도 합니다. 따라서 다시 한 번, 제목과 페이지 번호 사이의 관계는 명백할 것입니다.

단일 레벨 목차, 즉 챕터 이름만 있는 목차를 원할 때만 작동한다는 것을 깨닫기 전까지는 둘 중 하나가 좋은 옵션처럼 보였습니다. 그러나 목차에 하위 섹션을 표시하고 싶다면 좋은 옵션이 없었습니다. 테이블 요소는 계층적 데이터에 적합하지 않습니다., 정의 목록은 기술적으로 중첩될 수 있지만 의미 체계는 올바르지 않은 것 같습니다. 그래서 다시 그림판으로 돌아왔습니다.

나는 Julie의 접근 방식을 기반으로 목록을 사용하기로 결정했습니다. 그러나 나는 주문 목록(<ol>) 정렬되지 않은 목록(<ul>). 이 경우에는 순서가 지정된 목록이 더 적합하다고 생각합니다. 목차는 내용에 나타나는 순서대로 장과 부제목의 목록을 나타냅니다. 순서는 중요하며 마크업에서 길을 잃지 않아야 합니다.

불행히도, 순서가 지정된 목록을 사용한다는 것은 제목과 페이지 번호 간의 의미론적 관계를 잃는 것을 의미하므로 다음 단계는 각 목록 항목 내에서 해당 관계를 재설정하는 것이었습니다. 이를 해결하는 가장 쉬운 방법은 페이지 번호 앞에 "페이지"라는 단어를 삽입하는 것입니다. 이렇게 하면 다른 시각적 구분 없이도 텍스트에 대한 숫자의 관계가 명확해집니다.

다음은 내 마크업의 기초를 형성한 간단한 HTML 스켈레톤입니다.

<ol class="toc-list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol> <!-- subsection items --> </ol> </li>
</ol>

목차에 스타일 적용하기

사용할 계획인 마크업을 설정했으면 다음 단계는 몇 가지 스타일을 적용하는 것이었습니다.

먼저 자동 생성된 번호를 제거했습니다. 원하는 경우 자동 생성된 번호를 프로젝트에 유지하도록 선택할 수 있지만 책의 챕터 목록에 번호가 지정되지 않은 머리말과 뒷말이 포함되어 자동 생성된 숫자가 정확하지 않은 경우가 많습니다.

내 목적을 위해 수동으로 장 번호를 채운 다음 레이아웃을 조정하여 최상위 목록에 패딩이 없고(따라서 단락과 정렬) 포함된 각 목록이 두 개의 공백으로 들여쓰기됩니다. 사용하기로 했어요 2ch 어떤 글꼴을 사용할지 아직 확실하지 않았기 때문에 패딩 값을 사용했습니다. 그만큼 ch 길이 단위를 사용하면 어떤 글꼴을 사용하든지 간에 일관성이 없어 보일 수 있는 절대 픽셀 크기가 아닌 문자 너비를 기준으로 패딩을 사용할 수 있습니다.

다음은 내가 완성한 CSS입니다.

.toc-list, .toc-list ol { list-style-type: none;
} .toc-list { padding: 0;
} .toc-list ol { padding-inline-start: 2ch;
}

사라 수에 이단 WebKit 브라우저가 다음과 같은 경우 목록 의미 체계를 제거한다고 지적했습니다. list-style-type is none, 그래서 나는 추가해야했습니다 role="list" 그것을 보존하기 위해 HTML로:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>
CodePen 임베드 폴백

제목 및 페이지 번호 스타일 지정

내 취향에 맞는 목록으로 스타일을 지정했으면 이제 개별 목록 항목의 스타일 지정으로 넘어갈 차례였습니다. 목차의 각 항목에 대해 제목과 페이지 번호는 같은 줄에 있어야 하며 제목은 왼쪽에, 페이지 번호는 오른쪽에 정렬됩니다.

"문제없어요, 그게 flexbox의 용도입니다!"라고 생각할 수도 있습니다. 당신은 틀리지 않았다! Flexbox는 실제로 올바른 제목 페이지 정렬을 달성할 수 있습니다. 그러나 지시선을 추가할 때 몇 가지 까다로운 정렬 문제가 있으므로 대신 그리드를 사용하는 Christoph의 접근 방식을 선택했습니다. 그리드는 여러 줄 제목에도 도움이 되는 보너스입니다. 다음은 개별 항목에 대한 CSS입니다.

.toc-list li > a { text-decoration: none; display: grid; grid-template-columns: auto max-content; align-items: end;
} .toc-list li > a > .page { text-align: right;
}

그리드에는 두 개의 열이 있으며 그 중 첫 번째 열은 auto-컨테이너의 전체 너비를 채우고 두 번째 열을 뺀 크기입니다. max-content. 페이지 번호는 목차에서와 같이 오른쪽에 정렬됩니다.

이 시점에서 내가 한 유일한 다른 변경 사항은 "페이지" 텍스트를 숨기는 것입니다. 이것은 스크린 리더에 유용하지만 시각적으로 불필요하므로 전통적인 visually-hidden 수업 보기에서 숨기려면:

.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(100%); height: 1px; overflow: hidden; position: absolute; width: 1px; white-space: nowrap;
}

물론 해당 클래스를 사용하려면 HTML을 업데이트해야 합니다.

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

이 기반을 마련한 상태에서 제목과 페이지 사이의 리더에 대해 설명했습니다.

CodePen 임베드 폴백

점 지시선 만들기

리더는 인쇄 매체에서 매우 일반적이어서 CSS가 이미 지원하지 않는 이유가 무엇인지 궁금할 것입니다. 정답은: 그렇습니다. 글쎄.

실제로는 leader() 에 정의 된 함수 페이지 미디어 사양에 대한 CSS 생성 콘텐츠. 그러나 페이지된 미디어 사양의 대부분과 마찬가지로 이 기능은 브라우저에서 구현되지 않으므로 옵션으로 제외합니다(적어도 이 글을 쓰고 있는 시점에서는). 에 나열되어 있지도 않다. caniuse.com, 아마도 아무도 그것을 구현하지 않았고 계획이나 신호가 없기 때문일 것입니다.

다행히 Julie와 Christoph는 이미 각자의 게시물에서 이 문제를 해결했습니다. 점 지시선을 삽입하기 위해 둘 다 ::after 유사 요소 content 속성은 다음과 같이 매우 긴 점 문자열로 설정됩니다.

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .title::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

XNUMXD덴탈의 ::after 의사 요소는 페이지의 흐름에서 벗어나 다른 줄로 줄바꿈되는 것을 방지하기 위해 절대 위치로 설정됩니다. 각 줄의 마지막 점이 줄 끝에 있는 숫자와 같은 높이가 되기를 원하기 때문에 텍스트는 오른쪽에 정렬됩니다. (나중에 이것의 복잡성에 대해 더 자세히 설명합니다.) .title 요소는 상대 위치를 갖도록 설정되므로 ::after 의사 요소는 상자에서 벗어나지 않습니다. 한편, overflow 모든 추가 점이 보이지 않도록 숨겨져 있습니다. 결과는 점 지시선이 있는 예쁜 목차입니다.

그러나 고려해야 할 다른 것이 있습니다.

Sara는 또한 그 모든 점들이 스크린 리더에 대한 텍스트로 간주된다고 나에게 지적했습니다. 그래서 무엇을 듣습니까? "소개 도트 도트 도트..." 모든 도트가 발표될 때까지. 스크린 리더 사용자에게는 끔찍한 경험입니다.

해결책은 다음과 같이 추가 요소를 삽입하는 것입니다. aria-hidden 로 설정 true 그런 다음 해당 요소를 사용하여 점을 삽입합니다. 따라서 HTML은 다음과 같이 됩니다.

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title<span class="leaders" aria-hidden="true"></span></span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

CSS는 다음과 같이 됩니다.

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .leaders::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

이제 스크린 리더는 점을 무시하고 사용자가 발표되는 여러 점을 듣는 좌절감을 덜어줍니다.

CodePen 임베드 폴백

마무리

이 시점에서 목차 구성 요소는 꽤 좋아 보이지만 약간의 세부 작업이 필요할 수 있습니다. 시작하기 위해 대부분의 책은 시각적으로 하위 섹션 제목에서 장 제목을 오프셋하므로 최상위 항목을 굵게 표시하고 다음 장에서 하위 섹션을 구분하기 위해 여백을 도입했습니다.

.toc-list > li > a { font-weight: bold; margin-block-start: 1em;
}

다음으로 페이지 번호의 정렬을 정리하고 싶었습니다. 고정 너비 글꼴을 사용할 때는 모든 것이 괜찮아 보이지만 가변 너비 글꼴의 경우 리더 점이 페이지 번호 너비에 맞춰 조정되면서 지그재그 패턴을 형성할 수 있습니다. 예를 들어, 1이 있는 페이지 번호는 다른 페이지 번호보다 좁아서 지시선 점이 이전 또는 다음 줄의 점과 정렬되지 않게 됩니다.

목차의 숫자와 점이 잘못 정렬되었습니다.
HTML + CSS를 사용한 완벽한 목차

이 문제를 해결하기 위해 설정했습니다. font-variant-numerictabular-nums 따라서 모든 숫자는 동일한 너비로 처리됩니다. 또한 최소 너비를 다음으로 설정하여 2ch, 한 자리 또는 두 자리의 모든 숫자가 완벽하게 정렬되도록 했습니다. (다음으로 설정하고 싶을 수도 있습니다. 3ch 프로젝트에 100페이지가 넘는 경우) 페이지 번호에 대한 최종 CSS는 다음과 같습니다.

.toc-list li > a > .page { min-width: 2ch; font-variant-numeric: tabular-nums; text-align: right;
}
목차에서 정렬된 지시선 점.
HTML + CSS를 사용한 완벽한 목차

그리고 그것으로 목차 완성!

CodePen 임베드 폴백

결론

HTML과 CSS만 사용하여 목차를 만드는 것은 생각보다 어려웠지만 결과에 매우 만족합니다. 이 접근 방식은 장과 하위 섹션을 수용할 만큼 충분히 유연할 뿐만 아니라 CSS를 업데이트하지 않고도 하위 하위 섹션을 훌륭하게 처리합니다. 전반적인 접근 방식은 콘텐츠의 다양한 위치에 연결하려는 웹 페이지와 목차를 다른 페이지에 연결하려는 PDF에서 작동합니다. 물론 브로셔나 책에 사용하려는 경우 인쇄물로도 멋지게 보입니다.

목차 생성에 대한 훌륭한 블로그 게시물을 제공한 Julie Blanc와 Christoph Grabo에게 감사의 인사를 전하고 싶습니다. 또한 이 프로젝트에서 작업하면서 접근성 피드백을 제공한 Sara Soueidan에게도 감사의 말을 전하고 싶습니다.


HTML + CSS를 사용한 완벽한 목차 원래에 게시 CSS 트릭. 너는해야한다. 뉴스레터 받기.

타임 스탬프 :

더보기 CSS 트릭