Автоматическое добавление якорей к заголовкам
17 ноября 2019 г. 5:00
Технически в html якорь для заголовков может выглядеть так:
<h2 id="my-title">Мой заголовок <a href="#my-title">¶</a></h2> <p>Произвольный текст</p>
Результат выполнения такого кода:
Автоматически добавлять якорь к заголовкам можно как на стороне сервера, так и на стороне клиента. На стороне сервера придётся хранить дополнительный html-код, который будет загружаться из базы данных для отображения страницы, поэтому мне больше нравится посредством javascript добавлять якоря к заголовкам.
Постановка задачи
В зависимости от важных нужд вы можете изменить предлагаемый код. Я поставил перед собой следующие задачи.
С технической стороны
При наведении на заголовок должен появляться знак ссылки на якорь, а при отведении мышки этот знак скрывать.
1. Добавление якоря к заголовкам транслитом
<h2>Мой заголовок</h2> <p>Произвольный текст</p>
Должно преобразоваться в:
<h2 id="moi-zagolovok">Мой заголовок <a href="#moi-zagolovok">¶</a></h2> <p>Произвольный текст</p>
Обратите внимание, что надпись Мой заголовок
преобразуется в moi-zagolovok
, чтобы при копировании и вставке ссылки страницы красиво отображалось, а не заменой кириллицы на код, иначе http://my-site/#мой-заголовок
преобразился бы в http://my-site/#%D0%BC%D0%BE%D0%B9-%D0%B7%D0%B0%D0%B3%D0%BE%D0%BB%D0%BE%D0%B2%D0%BE%D0%BA
(хотя, некоторые приложения преобразуют такие ссылки, например, если вставить в сообщение в ВКонтакте).
2. Добавление ссылки на якорь к заголовкам с id
<h2 id="my-title">Мой заголовок</h2> <p>Произвольный текст</p>
Должно преобразоваться в:
<h2 id="my-title">Мой заголовок <a href="#my-title">¶</a></h2> <p>Произвольный текст</p>
3. Добавление ссылки на якорь к заголовкам по указанному id, который не содержится в заголовках
<div class="anchor_wr" id="my-title"> <img src="my_pic.jpg">Вспомогательный текст</img> <h2>Мой заголовок</h2> <p>Произвольный текст</p> </div>
Должно преобразоваться в:
<div class="anchor_wr" id="my-title"> <img src="my_pic.jpg">Вспомогательный текст</img> <h2>Мой заголовок <a href="#my-title">¶</a></h2> <p>Произвольный текст</p> </div>
По классу anchor_wr
можно определить id
и сформировать ссылку для заголовка. Это полезно, если нам нужно для заголовка добавить ссылку на якорь, который находится в любом месте документа.
Зачастую в этом случае определяется один заголовок (напр., h2
) внутри тега с классом .anchor
. Если будет несколько заголовков, то к каждому заголовку будет добавлена одинаковая ссылка, что тоже может быть полезно.
4. Добавление якоря к заголовкам по указанному data-anchor
<div id="my-title"> <p>Вспомогательный текст</p> <h2 data-anchor="my-title">Мой заголовок</h2> <p>Произвольный текст</p> </div>
Должно преобразоваться в:
<div id="my-title"> <p>Вспомогательный текст</p> <h2 data-anchor="my-title">Мой заголовок <a href="#my-title">¶</a></h2> <p>Произвольный текст</p> </div>
Это полезно, если нам нужно добавить ссылку на якорь, id
которого указывается в атрибуте data-anchor
.
5. Не добавлять ссылку на якорь при использовании класса .no_anchor
<div class="no_anchor"> <h2>Мой заголовок 1</h2> <p>Произвольный текст</p> </div> <h2 class="no_anchor">Мой заголовок 2</h2>
В этом случае добавленный класс .no_anchor к заголовку или блоку отменяет добавление заголовкам ссылки на якорь.
Со стороны адаптивности
Как правило для заголовков знак ¶
ссылки на якорь располагают справа (реже слева). Недостаточно просто добавить знак в конец заголовка, так как может быть случай, когда заголовок в несколько слов как раз входит в ширину элемента, где он расположен, но знак при этом перенесётся на другую строку. Это будет выглядеть примерно так:
Для предотвращения такого поведения можно последнее слово со знаком оборачивать в инлайновый тег со стилем запрещающем разрыв слов внутри тега:
<h2 id="moi-zagolovok">Мой очень длинный супер информативный <span style="white-space: nowrap;">заголовок <a href="#moi-zagolovok">¶</a></span></h2> <p>Произвольный текст</p>
Теперь будет отображаться лучше:
Но этого не достаточно. Если текст выравнивать по центру, то при наведении мышкой будет текст прыгать влево, то есть сам заголовок чуть смещаться влево из-за добавления знака, чтобы выравнить весь блок по центру.
Для решения данной проблемы можно для знака использовать свойство position: absolute;
. Тогда при любом выравнивании заголовка при наведении мышкой будет появляться знак без каких-либо дёрганий текста.
Программный код
Ниже приведён полный пример кода, который используется на данном сайте vivazzi.pro с поддержкой перевода. Функция для добавления ссылок на якорь вынесена в отдельный файл anchorify.js. Также подключён вспомогательный файл transliterate.js, который требуется для транслита заголовков там, где id
не указан.
<script src="jquery/jquery-2.2.0.min.js"></script> <script src="anchorify/transliterate.js"></script> <script> var anchorify_lang = { permalink: '{% trans 'Permalink to this headline' %}' <!-- Используйте свой способ перевода слов. В Django используется {% trans 'Permalink to this headline' %} --> }; </script> <script src="anchorify/anchorify.js"></script> <link rel="stylesheet" href="anchorify/anchorify.css"> <!-- 1. Добавление якоря к заголовкам транслитом --> <h2>Мой заголовок</h2> <p>Произвольный текст</p> <!-- 2. Добавление ссылки на якорь к заголовкам с id --> <h2 id="my-title-2">Мой заголовок 2</h2> <p>Произвольный текст</p> <!-- 3. Добавление ссылки на якорь к заголовкам по указанному id, который не содержится в заголовках --> <div class="anchor_wr" id="my-title-3"> <img src="my_pic.jpg">Вспомогательный текст</img> <h2>Мой заголовок</h2> <p>Произвольный текст</p> </div> <!-- 4. Добавление якоря к заголовкам по указанному data-anchor --> <div id="my-title-4"> <p>Вспомогательный текст</p> <h2 data-anchor="my-title-4">Мой заголовок</h2> <p>Произвольный текст</p> </div> <!-- 5. Не добавлять ссылку на якорь при использовании класса .no_anchor --> <div class="no_anchor"> <h2>Мой заголовок 1</h2> <p>Произвольный текст</p> </div> <h2 class="no_anchor">Мой заголовок 2</h2>
var ALPHABET_AND_DIGITS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; function transliterate(s, is_slug, valid_characters, use_dot) { function check_string(checked_string) { for(var i=0; i<checked_string.length; i++) { if (valid_characters.indexOf(checked_string[i]) == -1) return false } return true } if (is_slug == undefined) is_slug = false; if (valid_characters == undefined) valid_characters = null; if (use_dot == undefined) use_dot = false; if (!valid_characters){ valid_characters = ALPHABET_AND_DIGITS + '- '; if (!is_slug) valid_characters += '\\/._ '; if (use_dot && !('.' in valid_characters)) valid_characters += '.' } var capital_letters = { 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'E', 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M', 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', 'Ф': 'F', 'Х': 'H', 'Ц': 'Ts', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Sch', 'Ъ': '', 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya', ' ': is_slug ? '-' : '_' }, lower_case_letters = { 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'e', 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm', 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', 'ф': 'f', 'х': 'h', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch', 'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya' }, res = '', char = ''; s = s.toString(); for(var i=0; i<s.length; i++) { char = s[i].replace(/\s/g, ' '); if (char in lower_case_letters) { char = lower_case_letters[char] } else if (char in capital_letters){ char = capital_letters[char]; if (s.length > i + 1) { if (!(s[i + 1] in lower_case_letters)) char = char.toUpperCase() } else char = char.toUpperCase() } if (check_string(char)) { if (is_slug) char = char.toLowerCase(); res += char } } return res }
Я написал более универсальную функцию transliterate
, которая принимает параметры:
s - строка для преобразования is_slug - если true, то пробелы и нижние подчёркивания будут преобразованы в знак дефиса "-" (как раз нам это пригодится для создания ссылки на якорь). valid_characters - разрешённые символы, которые будут использованы для формирования ссылки use_dot - если true, то добавляет знак точки "." к разрешённым символам
$.each($('h2, h3, h4'), function () { if (!$(this).hasClass('no_anchor') && $(this).parents('.no_anchor').length === 0){ if (!$(this).attr('id') && !$(this).data('anchor') && $(this).parents('.anchor_wr').length === 0) $(this).attr({'id': transliterate($(this)[0].innerText, true)}); // проверяем, нужно ли добавлять к заголовку id $(this).hover(function () { var $anchor = $(this).find('.anchor'); // при первом наведении мышкой на заголовок ссылки пока нет, поэтому её нужно добавить if ($anchor.length === 0){ var link = $(this).data('anchor') || $(this).attr('id'); // пытаемся получить либо id заголовка, либо значение атрибута data-anchor // если ссылка не определена, пытаемся найти родительский элемент с классом .anchor_wr if (!link) { var $anchor_wr = $(this).parents('.anchor_wr'); if ($anchor_wr.length > 0) link = $anchor_wr.attr('id'); } // если ссылка определена, можно добавить её в заголовок if (link) { var parts = $(this).text().split(' '); // возвращаем массив слов заголовка if (parts) { var last_word = parts.pop(); // присваиваем переменной последнее слово из массива слов, удаляя его из массива parts $(this).html(parts.join(' ') + ' <span style="position: relative;">' + last_word + '</span>'); // оставшиеся элементы массива соединяем пробелом и добавляем последнее слово, обёрнутое тегом span $(this).find('span').append('<a class="anchor" href="#'+ link +'" title="'+anchorify_lang.permalink+'">¶</a>'); // добавляем ссылку в тег span } } } else { // при повторном наведении просто отображаем ссылку $anchor.css({'display': 'inline-block'}); } }, function () { // После отведения мышки от заголовка ссылку просто скрываем (а не удаляем, чтобы заново её не создавать) var $anchor = $(this).find('.anchor'); if ($anchor.length > 0) $anchor.css({'display': 'none'}); }); } });
Если вы захотите изменить список тегов или добавить свои теги, для которых нужно добавлять ссылку на якорь, то в первой строке кода вместо $('h2, h3, h4')
можно использовать, например, $('h2, h3, h4, h5, h6, my_tag')
.
.anchor {text-decoration: none;padding-left: 12px;font-size: .75em;position: absolute;line-height: initial;} @media (max-width: 767px) { .anchor {padding-left: 3px;} }
На больших экранах, как правило, справа отступ более 15px, поэтому сам знак можно размещать на расстоянии 12px от последнего слова. А при малой ширине (напр., менее 768px) экрана отступ от края 5px, поэтому и знак должен располагаться ближе, чтобы не вылезти за пределы ширины блока, в котором находится заголовок. Измените свойства стиля в соответствии с вашим дизайном сайта.
Теперь к вашим заголовкам будут автоматически добавляться ссылки на якорь!
Мой код не претендует на оптимальный. Например, в anchorify.js можно было обойтись без Jquery. Если вы доработаете и предложите свой более оптимизированный вариант кода, то буду рад!
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0