Content Security Policy

Popper.js — это мощная библиотека для управления позиционированием всплывающих элементов (tooltip, popover, dropdown) в браузере. Она позволяет точно рассчитывать положение элемента относительно его «опорного» (reference) элемента, обеспечивая динамическое обновление при изменении размеров или прокрутке страницы. Одним из важных аспектов работы с Popper.js является совместимость с политикой безопасности контента — Content Security Policy (CSP). CSP ограничивает возможность выполнения небезопасного кода, что особенно критично для библиотек, использующих динамическую генерацию стилей и скриптов.

Динамическое позиционирование и CSP

Popper.js активно использует вычисляемые стили для корректного отображения всплывающих элементов. Основной способ позиционирования реализуется через манипуляцию CSS-свойствами transform, top, left, right, bottom. В версиях Popper.js 2.x предпочтение отдается CSS transforms для более плавного и производительного перемещения:

import { createPopper } from '@popperjs/core';

const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');

createPopper(button, tooltip, {
  placement: 'top',
  modifiers: [
    {
      name: 'offset',
      options: {
        offset: [0, 8],
      },
    },
  ],
});

При использовании CSP важно, что Popper.js не требует вставки inline-стилей через eval или <style> с динамическим содержимым, что делает её безопасной при строгих политиках script-src 'self' и style-src 'self'.

Inline-стили и ограничения CSP

Popper.js применяет стили напрямую через element.style.property, а не через добавление CSS-классов с динамически генерируемыми правилами. Это соответствует большинству строгих CSP, если unsafe-inline для style-src не включен:

  • element.style.top = "10px" — безопасно
  • <style>...</style> или eval() — блокируется CSP

Важно понимать, что Popper.js не использует eval(), что делает библиотеку совместимой с CSP без дополнительных настроек. Единственным ограничением может стать использование сторонних плагинов или кастомных модификаторов, которые создают динамические стили через innerHTML или eval().

Применение CSP с Popper.js

Для корректной работы с Popper.js достаточно прописать базовые директивы CSP:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
  • default-src 'self' — разрешает загрузку ресурсов только с текущего домена.
  • script-src 'self' — предотвращает выполнение внешних скриптов.
  • style-src 'self' — запрещает вставку inline-стилей через <style> или style атрибут в HTML, но Popper.js применяет стили через JavaScript напрямую, что считается безопасным для CSP.

Если требуется более строгая политика, можно использовать nonce или hash для любых inline-стилей, генерируемых вручную.

Модификаторы Popper.js и CSP

Модификаторы (modifiers) — это плагины, которые изменяют поведение всплывающих элементов. Ключевые модификаторы:

  1. offset — смещает позицию всплывающего элемента относительно reference.
  2. preventOverflow — предотвращает выход tooltip за границы окна или родителя.
  3. flip — автоматически переворачивает позицию, если основной вариант не помещается.
  4. arrow — корректирует положение стрелки, указывающей на reference.

Все модификаторы работают через манипуляцию стилями элементов. CSP ограничивает только использование динамических скриптов, а не прямое изменение element.style, поэтому функциональность модификаторов сохраняется.

Примеры безопасного использования

createPopper(button, tooltip, {
  placement: 'bottom-start',
  modifiers: [
    { name: 'offset', options: { offset: [0, 12] } },
    { name: 'flip', options: { fallbackPlacements: ['top', 'right'] } },
    { name: 'preventOverflow', options: { padding: 5 } }
  ]
});

В этом примере все стили применяются через DOM API (element.style), что полностью совместимо с строгими CSP-директивами.

Особенности работы с Shadow DOM и CSP

Popper.js поддерживает позиционирование внутри Shadow DOM. CSP-директивы действуют в том же виде, что и на обычный DOM:

  • Inline-стили через JavaScript остаются допустимыми.
  • Вставка <style> внутри shadow root без nonce или hash блокируется.

Для работы с Shadow DOM достаточно использовать стандартные модификаторы, без необходимости изменения CSP.

Выводы по взаимодействию Popper.js и CSP

  • Popper.js полностью совместим с CSP при использовании базовых директив script-src 'self' и style-src 'self'.
  • Inline-стили в HTML не нужны, так как Popper.js применяет их через DOM API.
  • Модификаторы и динамическое позиционирование работают без нарушения CSP.
  • Любые кастомные скрипты, добавляющие динамические <style> или eval(), могут требовать nonce или hash.

Popper.js обеспечивает безопасное, динамическое позиционирование всплывающих элементов без компромисса с политикой безопасности контента.