Вопрос или проблема
Это мой первый пост на 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. Альтернативное решение
Чтобы успешно перенести шрифты из одного документа в другой, вам следует:
-
Копировать CSS стили: Убедитесь, что ваши стили @font-face корректно копируются из
sourceDoc.styleSheets
вtargetDoc.styleSheets
. Это наиболее надежный способ гарантировать, что шрифты будут доступны в целевом документе. -
Создание нового 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, поэтому тестирование в нескольких браузерах всегда будет полезным в процессе разработки.