Почему я не могу добавить FontFaces из одного FontFaceSet в другой FontFaceSet?

Вопрос или проблема

Это мой первый пост на StackOverflow, поэтому извините, если он не очень отточен и/или понятен.

Привет, я пытаюсь скопировать FontFaces из одного документа в другой. Метод, которым я это делаю, кажется, работает нормально в браузере Chrome, но не работает в Firefox и Safari (это единственные браузеры, которые я тестировал). Я сузил проблему до этого блока кода.

export async function copyFonts(sourceDoc: Document, targetDoc: Document): Promise<void> {
  const sourceFonts = sourceDoc.fonts;
  const targetFonts = targetDoc.fonts;

  sourceFonts.forEach((font) => {
    if (font instanceof FontFace) {
      targetFonts.add(font);
    }
  })

  await targetFonts.ready;
}

Конкретно, строка targetFonts.add(font) вызывает ошибку. Выводимая ошибка – это DOM-исключение, которое говорит:
FontFaceSet.add: Невозможно добавить шрифт в FontFaceSet, который пришел из правила @font-face

Я пытался добавить проверку, чтобы увидеть, является ли каждый FontFace в FontFaceSet sourceDoc.fonts экземпляром CSSFontFaceRule, и это возвращает false, что сбивает с толку, учитывая DOM-исключение.

Я также пытался сделать глубокую копию FontFace из sourceDoc и добавить это в FontFaceSet targetDoc, но проблема в том, что конструктор FontFace ожидает путь источника, а FontFaces, которые я получаю из sourceDoc, не имеют пути источника. У них есть только семья и описания.

Я также копирую CSS стили из sourceDoc в targetDoc. Это сделано, чтобы сохранить правильное расстояние и цвета, но я также подтвердил, что FontFaces из sourceDoc копируются в targetDoc через стили. Они просто не появляются в targetDoc, когда я ожидаю DOM, если полагаюсь только на копирование стилей, так что, насколько я могу судить, мне определенно нужно копировать FontFaceSet из sourceDoc в targetDoc.

Я бы ожидал, что смогу добавить FontFace в FontFaceSet нормально для всех браузеров. Я не нашел ничего, что указывало бы на то, что браузеры не могут поддерживать эту функциональность. Ближайшее, что я нашел, что похоже на мою проблему, это этот пост, но у меня установлена библиотека dom.iterable.

Кто-нибудь знает, в чем может быть проблема?

Ответ или решение

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

1. Природа FontFace

Веб-браузеры, такие как Chrome, Firefox и Safari, реализуют стандартные API для работы со шрифтами, однако их поведение может отличаться на этапе работы с объектом FontFace. FontFace представляет собой отдельный объект, который описывает шрифт, связанный с конкретным CSS правилом @font-face. Когда вы создаете шрифт, используя правило @font-face, браузер создает соответствующий объект FontFace.

2. Ошибка при добавлении FontFace

Вы encountered the following error message when attempting to execute targetFonts.add(font):

FontFaceSet.add: Can't add face to FontFaceSet that comes from an @font-face rule

Эта ошибка указывает на то, что вы не можете добавить экземпляр FontFace, который уже связан с @font-face в другом документе, в новый FontFaceSet. Это связано с тем, что такая привязка означает, что объект шрифта уже имеет свое место в контексте исходного документа, и браузеры не позволяют «перекладывать» эти объекты между разными FontFaceSet для предотвращения конфликтов и нарушения принципов дизайна.

3. Копирование FontFace

Попытка создания глубокого копирования FontFace предоставляет некоторые трудности. Причиной этого является то, что конструктор FontFace требует источник (source path), который отсутствует в объектах, полученных через sourceDoc.fonts. Формально говоря, FontFace содержит не только семейства и дескрипторы, но также и источник, который необходим для его инициализации в новом контексте.

4. Альтернативное решение

Чтобы успешно перенести шрифты из одного документа в другой, вам следует:

  1. Копировать CSS стили: Убедитесь, что ваши стили @font-face корректно копируются из sourceDoc.styleSheets в targetDoc.styleSheets. Это наиболее надежный способ гарантировать, что шрифты будут доступны в целевом документе.

  2. Создание нового FontFace: Если вы хотите управлять шрифтами непосредственно через FontFaceSet, вам следует создать новые экземпляры FontFace, передавая правильные пути к источнику шрифта и их атрибуты. Обратите внимание на необходимость использовать корректные пути к ресурсам шрифтов, чтобы обеспечить корректное отображение:

    sourceFonts.forEach((font) => {
     if (font instanceof FontFace) {
       const newFont = new FontFace(font.family, font.src, font.descriptors);
       targetFonts.add(newFont);
       newFont.load().then(() => {
         document.fonts.add(newFont);
       });
     }
    });

Заключение

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

Помните, что разные браузеры могут по-разному обрабатывать шрифты и API, поэтому тестирование в нескольких браузерах всегда будет полезным в процессе разработки.

Оцените материал
Добавить комментарий

Капча загружается...