Разработка текстового виджета: опыт Readymag

Автор: Илья Медведев, full stack developer в Readymag

В этой статье мы поделимся нашим опытом разработки текстового редактора в вебе, начиная с обзора существующих возможностей html/css и заканчивая best practices, которые мы вынесли во время разработки. Также мы расскажем о нюансах создания текстовых редакторов: как правильно работать с клавиатурой, выделением текста, вставкой из буфера обмена.

Readymag — это дизайн-инструмент, который позволяет создавать сайты и мультимедийные проекты в вебе без помощи разработчиков. При работе в нашем редакторе используются виджеты — и текстовый, конечно, самый популярный из них.

Со стороны пользователя он выглядит как поле для ввода текста, но за кажущейся простотой скрыто огромное количество нюансов. В этой статье расскажем о том, как работает ввод текста в вебе; расскажем о задачах, с которыми нам пришлось столкнуться и к каким решениям мы пришли.

Редактирование текста в вебе

Текстовый виджет в Readymag — это поле ввода текста и контролы для управления различными свойствами текста.

Сегодня в вебе есть несколько вариантов реализации полей ввода:

Input и Textarea идеально подходят для ввода текста внутри форм, но эти элементы не позволяют получить богатый опыт в работе с текстом. Для этого существует атрибут contenteditable, с помощью которого мы можем превратить практически любой элемент в редактируемый, а также использовать весь опыт стилизации текста внутри элемента.

Если вам нужно редактировать всю страницу целиком, вы можете воспользоваться document.designMode. Этот режим может быть полезен, например, при работе внутри iframe, т.к. вы можете редактировать все существующие элементы в документе.

Мы остановили свой выбор на атрибуте contenteditable, который включает в себя все необходимые возможности для редактирования текста.

Стилизация текста и свойства шрифтов

Для стилизации текста мы можем использовать все возможные опции, которые включает в себя CSS. Помимо общеизвестных свойств (таких, как шрифт, начертание, цвет, оформление), мы дали нашим пользователям возможность использовать OpenType font features.

С помощью свойства font-feature-settings появляется возможность включать необычные фичи шрифта. Например: ligatures, stylistic sets, fractions и т.д.

Рекомендую познакомиться с обзорной статьей о демонстрации всех фич шрифтов.

Современная типографика продвинулась далеко вперед: теперь в вебе вы можете использовать вариативные шрифты. Для этих целей существует свойство font-variation-settings.

Все фичи, которые вы хотите использовать, должны быть описаны в шрифте. Каким образом мы можем определить, позволяет ли выбранный шрифт использовать ту или иную фичу? Обратимся к спецификациям шрифтов. Каждый шрифт можно представить в виде таблиц с различной информацией, используемой при рендере символов.

Мы используем две таблицы для сбора информации о шрифте:

  • GSUB — Glyph Substitution Table. Данная таблица содержит в себе перечень данных по отрисовке глифов. Объект GSUB.featureList — это перечисление фич шрифта и их свойств. Данные в таблице выглядят следующим образом:

В этой таблице нам интересно поле tag, которое является наименованием фичи шрифта и говорит о том, что она доступна в данном шрифте. tag мы можем смело использовать в CSS-свойстве font-feature-settings.

  • fvar — Font Variations Table. Данная таблица является представлением вариативных свойств шрифта. Она выглядит так:

Каждый объект является свойством шрифта с описанием возможных значений (min/max/default) и локализованным названием (при наличии). Их мы используем в свойстве font-variation-settings.

Работа с клавиатурой

Ввод текста — один из самых важных аспектов в пользовательском опыте текстового виджета. Помимо шорткатов для работы с текстом есть и нетривиальные проблемы, с которыми нам пришлось столкнуться. Например, навигация по тексту с помощью стрелок.

В текстовом виджете есть вспомогательные иконки, которые показывают скрытые символы: например, специальные символы пробелов или мягкий перенос текста. Это обычные svg-иконки, вставленные в текст. Но если вы используете contenteditable, то эти иконки станут препятствием при навигации между параграфами — при нажатии на стрелки на клавиатуре, вы не сможете перейти на следующий параграф.

Мы нашли достаточно простое решение, которое реализовали с помощью span и псевдоэлемента before. Таким образом, браузер воспринимает иконку как текст и она не создает препятствий при навигации с помощью клавиатуры.

Шорткаты

Среди всех шорткатов, которые мы сделали доступными в текстовом виджете, есть два шортката для вставки текста.

Cmd + V — выполняет вставку текста из буфера обмена с сохранением стилей. Если текст был скопирован из какого-либо редактора (Pages, Notes, Microsoft Word, Google Docs и так далее), то у вас будет возможность получить html-представление данных из буфера обмена.

Данный html можно спарсить и вставить с сохранением первоначальных стилей. Получить данные в виде html вы можете следующим образом:

Дополнительно существует шорткат Cmd + Shift + V. При вставке текста с помощью данной комбинации клавиш, браузер оставит в payload только данные в виде text/plain, что позволяет вставить чистый текст без стилей. Эти шорткаты существуют в браузере по умолчанию, но нужно не забывать о реализации работы с ними.

Выделение текста и фокус

С помощью выделения текста пользователь может понять, какой именно фрагмент текста он сейчас редактирует. Представим простой пример: создадим поле ввода и добавим кнопку, с помощью которой мы управляем жирностью текста.

В этом примере вы можете выделить фрагмент текста и нажать кнопку Bold — при этом выделение в тексте будет сохранено и после нажатия. Но что, если наш пример станет сложнее, и мы добавим input, где пользователь будет устанавливать размер текста? Тогда фокус будет переведен на новый инпут с нашего текстового блока. Существует два варианта решения данной проблемы:

1. После каждого события на инпуте мы принудительно переводим фокус на текстовый блок. В таком случае, мы будем получать моргание выделения, если изменений будет достаточно много.

2. Мы можем поместить текстовый блок в iframe. Как известно, iframe имеет свой глобальный объект window, а, соответственно, и выделение внутри iframe будет сохраняться, когда пользователь переведет фокус на input снаружи этого iframe.

Перформанс при вводе текста

Немаловажную роль при работе с текстом играет отзывчивость интерфейса. Мы должны строго следить за значением fps при работе в редакторе. Особенно это касается случаев, когда пользователь вводит текст с высокой скоростью или изменяет, например, кегль шрифта. В Readymag существуют десктопный и мобильный вьюпорты: пользователь может создавать разные стили для одного и того же текста в разных вьюпортах. Конструктор в момент изменения текста производит различные вычисления, чтобы синхронизировать данные между ними. Добиться высокой отзывчивости возможно с помощью браузерных api: requestAnimationFrame и requestIdleCallback.

  • requestAnimationFrame вызывается каждый раз при обновлении экрана;
  • requestIdleCallback вызывается только в момент простоя браузера.

Это отличный способ выполнить трудоемкие операции, не блокируя основной поток.

Best Practices

В конце статьи — немного советов, которые помогут при разработке текстовых редакторов в вебе:

- Тщательно продумайте верстку результата. Вы сможете заранее понять, какие возможности вам нужны и как вы будете работать с элементами внутри текстового редактора.

- Настройте visual testing. Когда вы работаете с текстом, вы не можете полностью полагаться на результат тестирования с помощью снэпшотов. Вы можете получить правильный результат в тесте, ожидая заданный css у блока, но иногда результат может отличаться от предполагаемого.

- Следите за работой в разных браузерах. Хотя большинство из них хорошо поддерживают все новинки в вебе, могут возникать проблемы с отображением одних и тех же стилей в разных браузерах.

- Используйте фича-флаги для более безопасной разработки новых фич.

- Замеряйте fps в браузере при вводе текста. Не выполняйте тяжеловесные задачи в одном потоке.

- Не бойтесь экспериментировать.

- Попробуйте текстовый виджет в Readymag.

Полезные ссылки

0
1 комментарий
Vladimir Denisov

Горячие, мать его, клавиши.

P.S.
Ваш сайт делал псих.

Ответить
Развернуть ветку
-2 комментариев
Раскрывать всегда