Как сделать содержание (оглавление) в статье сайта/блога | HTML5

Оглавление в рамках статьи — это список ссылок. Только ссылки ведут не на другие страницы, а к подзаголовкам внутри одной длинной статьи.

Как создать оглавление внутри статьи блога

В начале заголовкам нужно задать id

<h2 id="steer">Бычок</h2>

Идет бычок, качается,
Вздыхает на ходу:
- Ох, доска кончается,
Сейчас я упаду!

<h2 id="bunny">Зайка</h2>

Зайку бросила хозяйка -
Под дождем остался зайка.
Со скамейки слезть не мог,
Весь до ниточки промок.

<h2 id="bear">Мишка</h2>

Уронили мишку на пол,
Оторвали мишке лапу.
Все равно его не брошу -
Потому что он хороший.

Код блока с содержанием, где href у ссылок точно такой же как id заголовков, за исключением символа #:

<nav class="toc">
  <h2>Содержание:</h2>
  <ul>
    <li><a href="#steer">Бычок</a>
    <li><a href="#bunny">Зайка</a>
    <li><a href="#bear">Мишка</a>
  </ul>
</nav>

Как сделать нумерованное содержание в статье сайта

Всё тоже самое, только ul нужно заменить на ol

<nav class="toc">
  <h2>Содержание:</h2>
  <ol>
    <li><a href="#steer">Бычок</a>
    <li><a href="#bunny">Зайка</a>
    <li><a href="#bear">Мишка</a>
  </ol>
</nav>

Многоуровневый нумерованный список HTML

Здесь уже нужна помощь CSS

<style>
.toc > ol {
  counter-reset: li;
}
.toc > ol > li {
  counter-increment: li;
}
.toc ol ol {
  counter-reset: lili;
}
.toc ol ol li {
  position: relative;
  list-style: none;
}
.toc ol ol li:before {
  content: counter(li) "." counter(lili) ".";
  counter-increment: lili;
  position: absolute;
  left: -2em;
}
</style>

<nav class="toc">
  <h2>Содержание:</h2>
  <ol>
    <li><a href="#raz">Четверостишия</a>
      <ol>
        <li><a href="#steer">Бычок</a>
        <li><a href="#bunny">Зайка</a>
        <li><a href="#bear">Мишка</a>
      </ol>
    <li><a href="#dva">Стихи</a>
      <ol>
        <li><a href="#r">Буква «Р»</a>
        <li><a href="#bullfinch">Снегирь</a>
      </ol>
</nav>

Логика призывает к такому построению тегов <h> в статье

<h2 id="raz">Четверостишия</h2>

<h3 id="steer">Бычок</h3>

Идет бычок, качается,
Вздыхает на ходу:
- Ох, доска кончается,
Сейчас я упаду!

<h3 id="bunny">Зайка</h3>

Зайку бросила хозяйка -
Под дождем остался зайка.
Со скамейки слезть не мог,
Весь до ниточки промок.

<h3 id="bear">Мишка</h3>

Уронили мишку на пол,
Оторвали мишке лапу.
Все равно его не брошу -
Потому что он хороший.

<h2 id="raz">Стихи</h2>

Подсвечивание разделов, к которым был сделан переход на CSS

При переходе к четверостишию "Зайка" страница не перематывается к началу стиха (см. тут). Чтобы более явно обозначить секцию, можно использовать псевдокласс :target.

<style>
section.blur:target {
  border-color: #f1f1f1;
  animation: anim .5s;
}
section {
  max-width: 20em;
  border: solid rgba(0,0,0,0);
  padding: 0 1em;
}
@keyframes anim { 
  0%, 100% { background: rgba(0,0,0,0); }
  50% { background: aqua; }
}
</style>

<section>
  <nav>
    <a href="#steer">Бычок</a>
    <a href="#bunny">Зайка</a>
    <a href="#bear">Мишка</a>
  </nav>
</section>

<section id="steer" class="blur">
<h2>Бычок</h2>
<p>Идет бычок, качается,
Вздыхает на ходу:
- Ох, доска кончается,
Сейчас я упаду!
</section>

<section id="bunny" class="blur">
<h2>Зайка</h2>
<p>Зайку бросила хозяйка -
Под дождем остался зайка.
Со скамейки слезть не мог,
Весь до ниточки промок.
</section>

<section id="bear" class="blur">
<h2>Мишка</h2>
<p>Уронили мишку на пол,
Оторвали мишке лапу.
Все равно его не брошу -
Потому что он хороший.
</section>

Фиксированное сверху меню и отступ от края окна браузера

Хэш-ссылка отматывает страницу к верхнему краю тега соответствующего id. Отчего получается, что фиксированное сверху меню закрывает часть элемента, в моём случае заголовок. Вот так.

Чтобы страница прокручивалась несколько выше элемента, нужно прописать тегу псевдоэлемент :before

<style>
nav { 
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  border: 4px solid #456;
}
h2:target:before {
  content: "";
  display: block;
  height: 2em;
  margin-top: -2em;
  visibility: hidden;
}
</style>

<nav>
  <a href="#steer">Бычок</a>
  <a href="#bunny">Зайка</a>
  <a href="#bear">Мишка</a>
</nav>

Фиксированное меню, в т.ч. для сайтов с параллакс эффектом, с подсветкой текущего пункта

Когда верхняя часть окна браузера проходит раздел веб-страницы, нужно выделить тот пункт меню, допустим поменять цвет его фона, нажав на который пользователь будет перемещён к началу этого раздела. Лучше посмотрите пример Смайлик улыбка. Для разнообразия на этот раз пункты меню отмечены зелёными точками и прикреплены к правой части страницы.

<style>
section { /* убрать схлопывание margin */ 
  display: inline-block;
  width: 100%;
}
nav { /* зафиксировать панель справа по центру */ 
  position: fixed;
  bottom: 50%;
  right: 1em;
  transform: translate(0, 50%);
}
nav a { /* стиль пунктов меню */ 
  display: block;
  margin-bottom: .5em;
  border: .5em solid green;
  border-radius: 100%;
}
.red { /* стиль активного пункта меню */ 
  border: .5em solid red;
}
</style>

<nav>
  <a href="#navsteer"></a>
  <a href="#navbunny"></a>
  <a href="#navbear"></a>
</nav>

<!-- все id начинаются с "nav" -->
<section id="navsteer">
<h2>Бычок</h2>
<p>Идет бычок, качается,
Вздыхает на ходу:
- Ох, доска кончается,
Сейчас я упаду!
</section>

<section id="navbunny">
<h2>Зайка</h2>
<p>Зайку бросила хозяйка -
Под дождем остался зайка.
Со скамейки слезть не мог,
Весь до ниточки промок.
</section>

<section id="navbear">
<h2>Мишка</h2>
<p>Уронили мишку на пол,
Оторвали мишке лапу.
Все равно его не брошу -
Потому что он хороший.
</section>

<!-- меньшее количество JavaScript не придумаешь -->
<script>
window.addEventListener('scroll', function(e) {
  var nav = document.querySelectorAll('section[id^="nav"]');
  for (var i = 0; i < nav.length; i++) { 
    document.querySelector('a[href="#' + nav[i].id + '"]').className=((1 >= nav[i].getBoundingClientRect().top && nav[i].getBoundingClientRect().top >= 1-nav[i].offsetHeight) ? 'red' : '');
  }
}, false);
</script>

Меню с плавной прокруткой страницы

Чтобы сделать плавную прокрутку к секции, нажав на ссылку, нужно к скрипту выше добавить:

var linkNav = document.querySelectorAll('[href^="#nav"]'),
    V = 2;  // скорость, может иметь дробное значение через точку
for (var i = 0; i < linkNav.length; i++) {
  linkNav[i].onclick = function(){
    var w = window.pageYOffset,
        hash = this.href.replace(/[^#]*(.*)/, '$1');
        t = document.querySelector(hash).getBoundingClientRect().top,
        start = null;
    requestAnimationFrame(step);
    function step(time) {
      if (start === null) start = time;
      var progress = time - start,
          r = (t < 0 ? Math.max(w - progress/V, w + t) : Math.min(w + progress/V, w + t));
      window.scrollTo(0,r);
      if (r != w + t) {requestAnimationFrame(step)} else {location.hash = hash}
    }
    return false;
  }
}

Для пользователей Blogger

Если использовать вкладку "Создать" при редактировании Сообщения, Blogger относительные ссылки вида

<a href="#steer">Бычок</a>
заменяет на абсолютные
<a href="https://www.blogger.com/blogger.g?blogID=0000000000000000000#steer">Бычок</a>

Чтобы избежать проблем, следует использовать абсолютные ссылки вида (текущая страница + хэш)

<a href="http://css.shpargalkablog.ru/2014/03/blog-post.html#steer">Бычок</a>
в f t
наверх ↑

24 комментария:

Александр
Нужная информация!!! Попробую использовать
NMitra
Хорошо, разовью тему в следующем посте.
Анонимный
Наталья, спасибо.

Скажите, пожалуйста, вы знаете как сделать так, чтобы страница не быстро перескакивала к целевому заголовку, а плавно (эластично) прокручивалась? (Я имею ввиду последний пример поста)
NMitra
Я поняла что вы имеете ввиду. Тоже об этом думала. Если у вас подключен JQuery, то http://stackoverflow.com/questions/7717527/jquery-smooth-scrolling-when-clicking-an-anchor-link

Если нужен только JavaScript, то отпишитесь, но код там получается не маленьким.
Анонимный
Наталья, спасибо за отклик.

Чтобы работал JQuery, надо подключать его библиотеки.

А код в этих библиотеках тоже не маленький.

С другой стороны, может не стоит изобретать велосипед. Но я читал, что jQuery не такой скоростной.

Может, самописный код будет шустрее.
NMitra
Я считаю, что подключать jQuery стоит если нужно несколько функций из библиотеки. Ради одной вешать весь арсенал не стоит. Я подумаю над скриптом.
NMitra
Сделала, есть замечания http://shpargalkablog.ru/2014/03/table-of-contents-html5.html#scroll ?
NMitra
А то уже и код, и результат примелькался, могла что-то упустить.
Vegan Boom
Сделала нумерованное оглавление внутри статьи блога http://veganboom.blogspot.com/2013/11/vegan-questions.html, но нумерация почему-то не отражается в оглавлении поста, хотя при редактировании сообщения вижу, что номера проставлены.

И второе. Поскольку у меня меню сверху закрывает начало заголовка закладки, то решила добавить css стиль, как вы советуете здесь http://shpargalkablog.ru/2010/09/postroenie-ssylok-v-html.html#zdes. Выставила там height: 3em; margin-top: -3em;
Почти нормально, но всё-таки как-то по-разному везде отступы отображаются (где-то есть пространство над заголовком, где-то заголовок чуть ли не обрезан). Подскажите, пожалуйста, что надо подправить, чтобы ссылка на закладку вела точно к началу соответствующего названия и чтобы моё главное меню не перекрывало это название.
NMitra
У вас в шаблоне прописано
ol, ul {
list-style: outside none none;
}
Сделайте приблизительно так
.toc ol {
list-style: decimal;
}

Пощелкала, проблем не увидела, вот только из-за скрипта у вас при переходе по хэш ссылке страница перезагружается.
Надежда Хачатурова
Очень помог Ваш материал. Не мудрствуя, сделала, чтобы было удобно на длинной странице переходить к нужному месту. Спасибо большое!
NMitra
Хочу материал дополнить парой ссылок, но как правило самое простое - самое востребованное. К тому же и Гугл, и Яндекс стараются учитывать такие меню в сниппетах.
Анонимный
Ссылки не открываются. Печалька((. Прошу посмотрите как сделано здесь http://html5.by/blog/scroll-effects/ . Особенно интересно эффект 8. Staging (Сцена). Если можно ознакомьте. Спасибо
NMitra
Какие именно ссылки не открываются?
Спасибо, прочитала.
Анонимный
Сейчас ссылки все работают. Почему-то раньше на работали и выдавали ошибку.
Тимур тим
Не хватает кнопки чтоб вернутьс яна верх
NMitra
<a href="#"></a>

http://shpargalkablog.ru/2011/05/kak-sdelat-ssylku-k-nachalu-stranitsy.html
Alex ZaJW
Здравствуйте! Полезная информация. Но Вы показали здесь не все пункты...
Содержание:
steer">Бычок
bunny">Зайка
bear">Мишка

Подскажите, пожалуйста, а как выделять (id) 4, 5... и до 10 пункта содержание?
NMitra
Здравствуйте, по аналогии: присваиваете id (не должен повторяться на странице) заголовкам, а потом ссылки на них ставите с #id

Наверно лучше всего вам посмотреть исходный код страницы: в адресную строку браузера введите

view-source:http://css.shpargalkablog.ru/2014/03/blog-post.html

(не работает в IE) . Подробнее http://shpargalkablog.ru/2014/05/see-html.html
Alex ZaJW
Спасибо за ответ. А по аналогии после - steer, bunny, bear - что-то следующее должно быть...?
NMitra
Что душе угодно, например, abrakadabra Главное, чтобы такого не было у других элементов в id
Alex ZaJW
Спасибо! Вы очень мне помогли!
Александр
Добрый день, нужно или нет добавлять к ссылкам содержания статьи тег rel="nofollow". Спасибо за ответ.
NMitra
Однозначно не нужно. Эти ссылки иногда попадают в сниппет, зачем запрещать переходить по ним роботу? Вес они всё равно никуда не передают.