На моем нынешнем веб-сайте я пытаюсь сделать все пиксельным с помощью спрайтовой графики и пиксельных шрифтов, чтобы он выглядел как можно ближе к игре. Проблема в том, что Chrome и Firefox предпочитают отображать пиксельные шрифты по-разному, и нет способа заставить их выглядеть единообразными. Это особенно происходит при попытке центрировать шрифт или использовать преобразование CSS. По умолчанию всегда используется сглаживание.
Для справки, вот шрифт, который я пытаюсь визуализировать динамически:
Firefox:

Chrome:

Обратите внимание, что в Firefox оно выглядит кристально четким, а в Chrome — размытым.
Я пытался попробовать все, чтобы это исправить. Хитрости CSS, HTML Canvas и Web GL – это лишь некоторые из них. Затем я наткнулся на несколько форумов по разработке игр, где обсуждалось использование атласа текстур для импорта шрифтов. Основная идея заключается в том, что у вас есть изображение листа спрайтов, содержащее все буквы вашего шрифта. Каждая буква считывается, разделяется, а затем присваивается соответствующей букве алфавита с помощью сценария, в результате чего появляется возможность динамически вводить буквы.
Я уверен, что есть способ сделать это с помощью Javascript, или, может быть, кто-то другой уже придумал решение, о котором я еще не подумал. Есть идеи?
РЕДАКТИРОВАТЬ: Вот небольшой фрагмент стека того, о чем я говорю:
:root { --коэффициент умножения: 1; --number-shadow: #002806; --text-shadow: #4b4b54; --размер шрифта: 16 пикселей; } @font-face { семейство шрифтов: Pixeltiny; источник: URL (https://old.sgxp.me/example/PixelTiny.ttf); } тело { трансформировать: транслироватьZ(0); } .sprite-page-container { поле: 20 пикселей 105 пикселей; } .спрайт-контейнер { дисплей: гибкий; flex-flow: перенос строк; оправдание-содержание: гибкий старт; отступ: 10 пикселей; минимальная высота: 200 пикселей; переход: 1с; } .sprite-box { ширина: Calc(117px * var(--коэффициент умножения)); высота: Calc(188px * var(--коэффициент умножения)); фоновое изображение: URL('https://old.sgxp.me/example/icon_image.svg'); поле: 10 пикселей; выбор пользователя: нет; переход: преобразование легкости входа-выхода .2s; текстовое оформление: нет; радиус границы: 4 пикселя; box-shadow: 10px 10px 0px rgba(0,0,0,0.7); анимация: Fadein-top .7s; } .sprite-box:hover { Transform: TranslateY(calc(-5px * var(--множитель-множитель))); анимация: Fadein-top .7s; } .sprite-page-container а { белый цвет; заполнение: 0; } .sprite-page-container a:hover { заполнение: 0; фоновое изображение: url("https://old.sgxp.me/example/icon_image.svg"); } .sprite-page-container a:visited { белый цвет; } .sprite-star-container { дисплей: гибкий; маржа слева: Calc(6px * var(--коэффициент умножения)); Margin-top: Calc(3px * var(--множитель-коэффициент)); маржа-дно: Calc(-9px * var(--множитель-коэффициент)); ширина: Calc(70px * var(--коэффициент умножения)); } .спрайт-звезда { высота: Calc(6px * var(--коэффициент умножения)); ширина: Calc(7px * var(--коэффициент умножения)); } .sprite-star:nth-child(n + 2) { поле слева: Calc(-1px * var(--множитель-множитель)); } .sprite-номер { семейство шрифтов: 'pixeltiny', моноширинный; размер шрифта: Calc(var(--font-size) * var(--коэффициент умножения)); белый цвет; выбор пользователя: нет; дисплей: гибкий; оправдание-содержание: правильно; высота строки: 0; поле-право: Calc(6px * var(--коэффициент умножения)); Margin-top: Calc(3px * var(--множитель-коэффициент)); text-shadow: Calc(1px * var(--множитель-коэффициент)) 0px var(--number-shadow), 0px Calc(1px * var(--множитель-коэффициент)) var(--number-shadow), Calc(1px * var(--коэффициент-умножения)) Calc(1px * var(--коэффициент-умножения)) var(--number-shadow); } .спрайт-текст { семейство шрифтов: 'pixeltiny', моноширинный; выбор пользователя: нет; размер шрифта: Calc(var(--font-size) * var(--коэффициент умножения)); line-height: Calc(7px * var(--множитель-коэффициент)); выравнивание текста: по центру; белый цвет; } .sprite-title { дисплей: гибкий; оправдание-содержание: центр; выровнять-элементы: по центру; дополнение-top: Calc(4px * var(--множитель-коэффициент)); маржа слева: Calc(5px * var(--коэффициент умножения)); поле-право: Calc(10px * var(--коэффициент умножения)); высота: Calc(15px * var(--коэффициент умножения)); ширина: Calc(109px * var(--коэффициент умножения)); переполнение-обертка: где угодно; } .спрайт-изображение { дисплей: гибкий; оправдание-содержание: центр; выровнять-элементы: по центру; рендеринг изображения: пиксельный; события указателя: нет; высота: Calc(71px * var(--коэффициент умножения)); ширина: Calc(103px * var(--коэффициент умножения)); Margin-top: Calc(5px * var(--множитель-коэффициент)); маржа-слева: Calc(7px * var(--коэффициент умножения)); поле-право: Calc(6px * var(--коэффициент умножения)); объектное соответствие: обложка; переполнение: скрыто; } .sprite-image > img { фильтр: drop-shadow(calc(10px * var(--коэффициент-умножения)) Calc(10px * var(--коэффициент-умножения)) 0px rgba(0,0,0,0.7)); Transform: Scale(calc(1 * var(--коэффициент умножения))); } .sprite-автор { дисплей: гибкий; оправдание-содержание: центр; выровнять-элементы: по центру; Margin-top: Calc(-2px * var(--множитель-множитель)); поле слева: Calc(13px * var(--коэффициент умножения)); поле-право: Calc(12px * var(--коэффициент умножения)); маржа-дно: Calc(0spx * var(--коэффициент умножения)); высота: Calc(26px * var(--коэффициент умножения)); ширина: Calc(93px * var(--коэффициент умножения)); переполнение-обертка: где угодно; } .sprite-статистика { дисплей: гибкий; оправдание-содержание: гибкий старт; выровнять-элементы: гибкий старт; Margin-top: Calc(4px * var(--множитель-коэффициент)); маржа-слева: Calc(24px * var(--коэффициент умножения)); поле-право: Calc(3px * var(--множитель-коэффициент)); ширина: Calc(110px * var(--коэффициент умножения)); } .sprite-stats:nth-child(n+2) { высота: Calc(5px * var(--коэффициент умножения)); } @keyframes Fadein-top { 0% { непрозрачность: 0; трансформировать: TranslateY(-50px);} 50% { непрозрачность: 0; трансформировать: TranslateY(-50px);} 100% { непрозрачность: 1; трансформировать: транслироватьY(0); } 001 Пример Пример Пример Пример Пример Пример
Как видите, я динамически помещаю текст примера поверх моего SVG-изображения. Все в SVG выглядит нормально, но когда я вставляю текст, Chrome отображает его с этим странным сглаживанием шрифта.
Вот пример того, о чем я говорил, с частью атласа текстур. Во второй половине страницы вы можете видеть, что они используют лист спрайтов со всеми выложенными буквами шрифта, а затем используют код для присвоения каждой части букве и вставки ее в свой пример WebGL. Я хотел бы сделать то же самое, за исключением того, что в моем случае он динамически ссылается на то, что я набрал, и вставляет его туда, где находится мой пример текста.