rehype-autolink-headings: автоматические ссылки

Для работы с автоматическим добавлением ссылок к заголовкам на основе Markdown и HTML используется плагин rehype-autolink-headings. Он интегрируется в цепочку обработки через unified, вместе с remark и rehype, что позволяет конвертировать Markdown в HTML с автоматически создаваемыми якорными ссылками.

Установка выполняется через npm:

npm install rehype-autolink-headings

Подключение в цепочку обработки выглядит следующим образом:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';

const processor = unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeAutolinkHeadings, { beh * avior: 'wrap' })
  .use(rehypeStringify);

Здесь behavior определяет способ добавления ссылки:

  • wrap — оборачивает текст заголовка в <a> с соответствующим id.
  • prepend — добавляет ссылку перед заголовком.
  • append — добавляет ссылку после заголовка.

Настройка идентификаторов заголовков

По умолчанию rehype-autolink-headings использует id, который создается на основе текста заголовка. Для управления формированием идентификаторов можно использовать плагин rehype-slug:

import rehypeSlug from 'rehype-slug';

const processor = unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeSlug)
  .use(rehypeAutolinkHeadings, { beh * avior: 'wrap' })
  .use(rehypeStringify);

rehype-slug генерирует уникальные идентификаторы для каждого заголовка, предотвращая дублирование и обеспечивая корректные ссылки.


Настройка внешнего вида ссылок

С помощью параметра properties можно добавить атрибуты к ссылкам, например класс или aria-label:

.use(rehypeAutolinkHeadings, {
  beh * avior: 'append',
  properties: {
    className: 'heading-anchor',
    ariaLabel: 'Ссылка на этот заголовок'
  }
})

Это позволяет легко стилизовать ссылки через CSS:

.heading-anchor {
  text-decoration: none;
  margin-left: 0.5em;
  color: #007acc;
}

Использование и комбинация с иконками

Часто к заголовкам добавляют визуальный элемент (иконку) для обозначения ссылки. Для этого используется опция content:

import { h } from 'hastscript';

.use(rehypeAutolinkHeadings, {
  beh * avior: 'append',
  content: h('span', { className: 'icon-link' }, '#')
})

С помощью CSS можно стилизовать иконку:

.icon-link {
  font-size: 0.8em;
  color: #999;
  margin-left: 0.25em;
}

Пример полной цепочки обработки

Markdown → HTML с автоссылками:

import fs from 'fs';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeSlug from 'rehype-slug';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import rehypeStringify from 'rehype-stringify';
import { h } from 'hastscript';

const markdown = fs.readFileSync('example.md', 'utf8');

const html = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeSlug)
  .use(rehypeAutolinkHeadings, {
    beh * avior: 'append',
    content: h('span', { className: 'icon-link' }, '?'),
    properties: { className: 'heading-link' }
  })
  .use(rehypeStringify)
  .process(markdown);

fs.writeFileSync('example.html', html.toString());

Результатом будет HTML, где каждый заголовок <h1><h6> имеет уникальный id и ссылку с иконкой, добавленную после текста заголовка.


Поведение с разными уровнями заголовков

rehype-autolink-headings применяет одинаковое поведение ко всем заголовкам, но при необходимости можно фильтровать уровни заголовков с помощью функции test:

.use(rehypeAutolinkHeadings, {
  beh * avior: 'append',
  test: (node) => node.tagName === 'h2' || node.tagName === 'h3',
})

Это позволяет добавлять ссылки только к определённым уровням заголовков, игнорируя, например, <h1>.


Интеграция с CSS и анимацией

Автоссылки можно визуально выделять при наведении. Для этого применяется CSS:

.heading-link {
  opacity: 0;
  transition: opacity 0.2s;
}

h2:hover .heading-link,
h3:hover .heading-link {
  opacity: 1;
}

Таким образом, ссылки появляются только при наведении на заголовок, сохраняя чистоту визуального оформления документа.


Особенности и ограничения

  • При использовании wrap весь текст заголовка оборачивается в <a>. Это может повлиять на стили заголовка, поэтому важно проверять отображение.
  • Для корректной генерации id необходимо использовать rehype-slug. Без него дублированные заголовки получат одинаковый id.
  • Плагин не обрабатывает заголовки, созданные динамически после рендеринга HTML. Он работает только на этапе компиляции через unified.

Эта комбинация rehype-autolink-headings, rehype-slug и кастомизации контента позволяет создать полностью интерактивные, визуально аккуратные заголовки с ссылками для любого Markdown-документа, интегрируемого в веб-приложение.