Автоматическое добавление якорей к заголовкам
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