etpgrf
Описание
etpgrf — effortless typography for web / единая типографика для веба
Языки
- Python100%
etpgrf — единый типограф для веба / effortless typography for web
Типограф для веба
Экранная типографика для веба — способствует повышению читабельности текста в интернете, приближая его к печатной типографике.
Репозитории / Repositories
Исходный код доступен на нескольких площадках:
Демонстрация / Demo
Работа etpgrf-типографа представлена по адресу: typograph.cube2.ru. Подготовьте верстку вашего текста, сайтов, статей и постов к публикации в интернете за один клик.
Установка
Быстрый старт
Кодировки и html-мнемоники
Внутри типографа используется кодировка UTF-8. Но при использовании может быть другие кодировки (например,
для русскоязычных текстов все ещё могут использовать Windows-1251). При таких кодировках, для отображения в браузерах
некоторых специфических символов (например, кавычек, тире, стрелочек, математических символов) используют
html-мнемоники (например, для длинного тире, для открывающей кавычки-ёлочки и т.д.).
Библиотека etpgrf имеет три режима работы с кодировками:
- Режим
— весь вывод осуществляется в кодировке UTF-8. ВЕСЬ! Включая невидимые символы, типа неразрывных и нулевых пробелов, мягких переносов и т.д. Это не всегда удобно зато типографированый текст (строки) будет максимально компактен и занимать меньше места в памяти. В этом режиме в html-мнемоники преобразуются только опасные символы:unicode— знак меньше<;<— знак больше>;>— амперсанд&;&— двойные кавычки";"— одинарные кавычки (апостроф)'.'
- Режим
— вывод осуществляется в кодировке UTF-8, но наиболее критичные символы заменяются на html-мнемоники. Они невидимы или неотличимы друг от друга на экране:mixed— мягкий перенос (Soft Hyphen);­— неразрывный пробел (Non-Breaking Space); — полужирный пробел (En Space) — широкий пробел (Em Space) — цифровой пробел; — пунктуационный пробел; — межсимвольный пробел; — пробел "толщина волоса" (Hair Space); — негативный пробел (Negative Space);​— пробел нулевой ширины (без объединения) (Zero Width Non-Joiner);‍— нулевая ширина (с объединением) (Zero Width Joiner);‌— изменение направления текста на слева-направо (Left-to-Right Mark);‎— изменение направления текста на направо-налево (Right-to-Left Mark);‏— дефис (Hyphen);‐— средний пробел (Medium Mathematical Space); — неразрывный пробел (No-Break Space);⁠— невидимый знак умножения (Invisible Times) для семантической разметки математических выражений;⁢— невидимая запятая (Invisible Comma) для семантической разметки математических выражений.⁣
- Режим
— применяются все возможные html-мнемоники (кроме русских букв) и символов первой половины ASCII (плюс, минус, знак равенства, знаки препинания и т.д.).mnemonic
Переключение режимов осуществляется с помощью параметра при конфигурировании типографа:
ВАЖНО:
- Если в тексте уже есть html-мнемоники, они будут преобразованы в unicode, и после обработки типографом будут заменены на html-мнемоники, соответствующие текущему режиму работы типографа.
- Некоторым символам соответствуют несколько html-мнемоник. Например,
(стрелочка влево) может кодироваться как→,→,→,&rightarrowи→. Типограф будет использовать самое короткое из них (для компактности), а значит:→- если в исходном тексте были html-мнемоники, то они будут заменены на более короткие;
- если html-мнемоники использовались как элементы семантической разметки (например, для математических выражений),
то после замены на более короткие html-мнемоники, текст может потерять такую семантику. Например
(F = A ⋂ B) будет преобразовано вF = A ⋂ B;F = A ⋂ B
- Мнемоники для русских букв не используются в типографе. Все мнемоники русских букв будут преобразованы в русские буквы и останутся в тексте в виде русских букв.
- Все исходные html-мнемоники, которые превращаются в два unicode-символа будут превращены обратно в мнемоники каждый
как отдельный символ. Например, множество собственное другого подмножества
в unicode отображается двумя символами⊊︀и превратится в\u228a\ufe00. Символ⊊\ufe00— это невидимый символ, селектор варианта начертания (Variant Selector), который изменяет начертание предыдущего символа и для него нет html-мнемоники. К счастью, в стандарте таких мнемоник (превращающихся в два символа) исчезающе мало и они крайне редко применяются в тексте, поэтому это не должно вызывать проблем.\ufe00
Переносы слов
Обычно в основе переносов слов лежит фонетический принцип — деление по слогам и морфемный принцип — деление по морфемам (приставки, корни, суффиксы, окончания). В типографе etpgrf реализован эвристический подход к переносу слов, основанный на фонетических правилах. Он не является строгим и не учитывает все нюансы языка, но обеспечивает вполне приемлемое качество для большинства случаев. Особенно если "неразрывные" блоки задать достаточно длинными (и именно это и требуется от хорошего типографа, ведь перенос трех-четырех букв слова на новую строку почти не улучшит читабельность и внешний вид текста).
Настройки по умолчанию для переноса слов (в ):
- Длина слова которое не подлежит переносам (
) — 12 символов.MAX_UNHYPHENATED_LEN - Длина части слова, которое недопустимо переносить или оставлять на строке ("хвост", "сироты")
(
) — 5 символовMIN_TAIL_LEN
Управление этими параметрами осуществляется через переопределение. Например:
Или через параметры конфигурации переносов типографа:
Результат обработки текста с переносами будет выглядеть так:
Предлоги, союзы и частицы
Правилом хорошего тона в любой типографике считается, когда короткие слова, такие как предлоги, союзы и частицы, не остаются в конце строки в одиночестве («висеть»). Это ухудшает читаемость.
Типограф автоматически решает эту проблему, «приклеивая» такие слова к последующему слову с помощью
неразрывного пробела ().
→в домев доме→и сказали сказал
Это правило работает для коротких слов в русском, старорусском и английском языках.
Кроме того, обрабатываются и постпозитивные частицы (например, , , ), которые, наоборот, для улучшения
читабельности, «приклеиваются» к предыдущему слову:
→сказал бысказал бы
Кавычки
В текстах кавычки бывают двух видов: «ёлочки» (для русского языка) и “лапки” (для английского языка). В типографе реализована автоматическая замена кавычек на соответствующие типографские символы в зависимости от языка текста.
Большинство типографов при обработке кавычек находят парные (и определяют вложенность). В etpgrf же реализован другой подход. Он ищет и обрабатывает кавычки, которые находятся рядом со словами. То есть какие-то буквы следуют слева или справа от кавычки.
Преобразование рядом с цифрами (например, когда обозначаются дюймы () или секунды ()) не производится. Также
не обрабатываются кавычки, окруженные пробелами. Все кавычки, которые в исходном тексте уже были оформлены в виде
«ёлочек» или “лапок” — тоже не обрабатываются.
ВАЖНО1: По правилам орфографии перед закрывающей кавычкой разрешены только определенные знаки препинания:
вопросительный (?), восклицательный (!) знаки и многоточие (…). Такие конструкции используются для цитат. Это учтено
в etpgrf, и кавычки будут обработаны: будет преобразовано в . По правилам пунктуации, точка перед закрывающей кавычкой не допускается, но существуют
исключения, когда перед кавычкой стоит сокращение (например, , ). В таких случаях точка сохраняется:
→ . Типограф допускает точку перед закрывающей
кавычкой.
ВАЖНО2: Если в настройке типографа указано несколько языков (), то кавычки будут преобразованы по правилам
для языка, который идет первым в списке. Например, для кавычки будут преобразованы в «ёлочки».
Если при типорафировании преобразование не требуется, то можно обработку кавычек можно отключить с помощью
параметра :
Компоновка (тире, диапазоны, инициалы, единицы измерения, сокращения и т.п.)
После того как псевдографика заменена на правильные символы, в дело вступает модуль компоновки (layout), который отвечает за расстановку неразрывных и тонких пробелов. Он применяет несколько важных правил для улучшения читаемости.
Тире
По правилам русской типографики, длинное тире () должно отбиваться пробелами от соседних слов. Чтобы тире не "повисло"
в начале строки и визуально не смешивалось с диалогами, etpgrf заменяет пробел перед тире на неразрывный ().
→слово — словослово — слово
В английской типографике, наоборот, тире пишется слитно. Типограф учитывает это при указании языка .
→word — wordword—word
Если минус или диапазон стоят между числами (арабскими или римскими), то это считается обозначением числового диапазона
(или отрицательным числом, или математическим выражением), и никаких изменений не производится. Неважно есть пробелы
вокруг тире/минуса или нет. Если между цифрами тире, то это тоже считается диапазоном и неразрывные пробелы не ставятся:
→ , → ,
Если минус стоит перед числом (например, ), то это считается отрицательным числом, и перед ним ставится неразрывный
пробел: → .
Инициалы и акронимы
Чтобы инициалы не отрывались друг от друга и от фамилии при переносе строки, типограф расставляет между ними специальные пробелы:
- Неразрывный пробел (
) ставится между фамилией и инициалом/инициалами ( →А. Пушкин). Неважно стоят ли инициалы перед фамилией или после неё. Важно наличие точки и буквы (инициала), написанного с заглавной буквы.А. Пушкин - Тонкая шпация (
) ставится между самими инициалами, если они написаны слитно, для улучшения внешнего вида ( →Пушкин А. С.). Число инициалов не ограничено (Пушкин А. С.→J.R.R. Tolkien), наличие или отсутствие пробелов между инициалами в исходном тексте неважно.J. R. R. Tolkien - Акронимы, написанные через точку (не слитно, например, Н.Л.О.), разделяются так же, как инициалы, через тонкую шпацию
(
→Н.Л.О.). Наличие или отсутствие пробелов между буквами в исходном тексте неважно.Н. Л. О.
Это правило может давать побочные эффекты (в частности, тонкая шпация не является неразрывным пробелом, и в длинных
акронимах может привести к разрыву строки). Поэтому его обработку можно отключить с помощью параметра
:
Единицы измерения
Типограф предотвращает отрыв единиц измерения от чисел, ставя между ним и предшествующей цифрой неразрывный пробел. Это работает для:
- Простых единиц:
→100 км.,100 км.→-5 °C'-5 °C - Составных единиц:
→120 кв.м.,120 кв. м.→50 тыс. руб.Пробелы (есть они или нет) между составными частями единицы изменения не важны. Между частями составной единицы измерения ставится тонкая шпация (50 тыс. руб.).  - Единиц с предлогом:
→№ 5,№ 5→§ 7,§ 7→$ 100$ 100 - Чисел, записанных и арабскими, и римскими цифрами:
→V в.н.э.V в. н. э. - Если между единицами изменений есть математические символы (например, умножение или деление):
→10 км / ч(неважно есть пробелы вокруг10 км/чили нет). Распознаются и другие символы:/,·,*,×.÷ - Символы
,x,X,х, стоящие между двумя числами, заменяются на знак умноженияХ, чтобы выражения вида×или100x100корректно обрабатывались и выглядели типографски правильными (100 х 100или100×100).100 × 100
Библиотека "знает" множество стандартных единиц для русского и английского языков. Но не все. Вы можете расширить этот
список, передав свои кастомные единицы через параметр :
Если нужно отключить распознавание и обработку единиц измерения:
Сокращения
Типограф также обрабатывает распространённые русскоязычные сокращения, чтобы они корректно отображались и не разрывались при переносе строк. Правила делятся на два типа:
- Финальные сокращения. Сокращения, которые обычно стоят в конце фразы (например, и т. д., и т. п.),
обрабатываются особым образом: их части «склеиваются» тонкой шпацией, а перед всей конструкцией ставится неразрывный
пробел, чтобы она не «повисла» на новой строке.
→...и так далее, и т. д.Это правило работает независимо от того, как сокращение было написано в исходном тексте (т.д. или т. д.)....и так далее, и т. д. - Препозиционные сокращения. Сокращения, которые стоят перед другим словом (например, и. о. директора, т. е. сказать),
также «склеиваются» внутри, но неразрывный пробел ставится после них, чтобы привязать их к последующему слову.
→Назначить и. о. директораНазначить и. о. директора
Библиотека знает небольшой набор самых распространённых сокращений. Но не все, а некоторые принципиально невозможны
к обработке. Например, сокращение может оказаться как финальным (в значении «и так далее»), так и препозиционным
(в значении «профессор» или «проспект»). Так же типограф не обрабатывает сокращения, связанные с адресами (ул., д.,
кв., пл., наб. ...) так как они могут быть как финальными, так и препозиционными.
Висячая типографика
Висячая типографика — это приём из классической вёрстки, когда некоторые знаки препинания (кавычки, скобки, иногда тире и маркеры списков) выносятся на левое (и иногда и по правому) поле текста. Это создаёт идеально ровный край не по формальным границам знаков, а по оптическому краю — по первым буквам строк. Текст выглядит гораздо аккуратнее и профессиональнее.
Интернет публикации (да и бумажные издания) практически игнорируют висячую типографику. Но иногда это отличный
инструмент для акцентной типографики: крупные заголовки, цитаты, выносы, подписи к иллюстрациям, оформленные с помощью
висячей типографики, выглядят гораздо эффектнее. В современном CSS есть свойство , которое должно
делать всё это автоматически. Но на сегодняшний день (конец 2025) его поддержка браузерами практически нулевая (кроме
Safari), поэтому на него полагаться нельзя. Поэтому в типографе etpgrf реализация висячей типографики осуществляется
через оборачивание висячих символов в специальные HTML-теги с CSS-классами.
Оборачивая "висячий" символ или слово в и применяя к нему, например, отрицательный или
(), мы можем сместить сам символ, но нужно ещё и
сохранить расстояние до соседнего слова. Поэтому типограф оборачивает не только сам висячий символ, но и ближайшее слово
(до пробела или границы узла), а также при необходимости, окружающий пробел. Сама визуальная компенсация оформляется через
отрицательные / в CSS-классах — никаких , чтобы не нарушать поток текста.
Учтите, что набор символов, попадающих в , помимо обычного пробела включает табуляции, переводы
строки и множество тонких/математических пробелов. Именно поэтому компенсирующие обёртки иногда захватывают
символы на границе узлов или переносов и сохраняют корректный визуальный зазор.
По умолчанию эта функция висячей типографики отключена. Чтобы её включить, нужно задать параметр
при конфигурировании типографа (по умолчанию ):
Параметр может принимать следующие значения:
илиNone— функция отключена (по умолчанию);Falseили'left'— включены только левые висячие символы (выравнивание по левому краю);True— включены только правые висячие символы (выравнивание по правому краю).'right'
Значения недоступно, потому что совмещение левой и правой выверки одновременно приводит к конфликтам
с размещением пробелов и делает невозможным контролировать визуальное выравнивание (см. блок про ).
Также через можно задать список тегов, внутри которых висячая типографика будет применяться
(всегда в режиме ). Это не рекомендованный способ, потому что он предполагает знание структуры HTML и неизбежно
выпадает из общей логики вложенности и пробельных узлов.
Как работает оборачивание
Процессор висячей типографики запускается после всех текстовых преобразований и работает с деревом BeautifulSoup. Он ищет
последовательности «пробел + висячий символ» для левого выравнивания и «висячий символ + пробел» для правого,
чтобы обернуть нужные фрагменты в пары и не допустить «сиротства» символов. Порядок действий можно описать так:
- Для
:hanging_punctuation='left'- если символ стоит в начале текстового узла (без пробелов слева), оборачивается только сам символ и следующее
слово (
);<span class="etp-laquo">«АукЫон»</span> - если перед "висячим" символом внутри узла есть пробел, то пробел и слово слева от него оборачивается
в
(компенсирующий пробел), а сам "висячий" символ вместе со словом справа — в<span class="etp-sp-laquo">слово </span>;<span class="etp-laquo">...</span> - если компенсирующий пробел оказался в соседнем узле (слева), то он тоже оборачивается в
, чтобы не нарушить последовательность;etp-sp-* - если слева от "висячего" символа пробел является "неразрывным пробелом" (
, нулевой неразрывный пробел, узкий неразрывный пробел или любой "не пробельный" символ) — это означает, что "висячий" символ не может "вывешиваться" в начале строки и оборачивания в не проиходит.<span>
- если символ стоит в начале текстового узла (без пробелов слева), оборачивается только сам символ и следующее
слово (
- Для
:hanging_punctuation='right'- слово с "висячим символом" и слово слева оборачивается в соответствующий класс (
,.etp-raquoи т.д.);.etp-rpar - пробел сразу после символа (справа) получает класс
,etp-sp-raquoи т.д., чтобы сохранить переносную ширину и аккуратно компенсировать смещение;etp-sp-rpar - если компенсирующий пробел оказался в соседнем узле (справа), то он тоже оборачивается в
, чтобы не нарушить последовательность;etp-sp-* - если справа от "висячего" символа пробел является "неразрывным пробелом" (
, нулевой неразрывный пробел, узкий неразрывный пробел или любой "не пробельный" символ) — это означает, что "висячий" символ не может "вывешиваться" в конце строки и оборачивания в не проиходит.<span>
- слово с "висячим символом" и слово слева оборачивается в соответствующий класс (
Пример вывода для :
Пример вывода для :
CSS для висячих символов
Предлагаемый, начиная с etpgrf v0.1.6, CSS теперь работает только с и , без .
Компенсирующие пробелы получают собственные классы, поэтому их компенсация контролируется отдельно, а не встроена
в сам висячий символ. Убедитесь, что эти стили подключены к странице и не конфликтуют с , который
увеличивает пробелы между словами по всей строке, делают текст менее удобным для чтения и не пригодны
для выравнивания.
Комментарии: Двухстороннее выравнивание текстового блока с помощью стиля в принципе плохо совместим концепцией типографики — он растягивает или сжимает пробелы по всей строке (а это пробелы между словами) и уже этими, переменными, пробелами, делает текст трудночитаемым. Если же вы используете для выравнивания текста по ширине, то, чтобы сохранить оптимальную читаемость текста, включать висячую типографику не рекомендуется.
Известные особенности и ограничения
При обработке сложного HTML-кода типограф стремится сохранить структуру документа, но некоторые пограничные случаи могут обрабатываться не так, как ожидается. В частности:
- Обработка на стыке тегов: Правила, требующие анализа контекста (например, расстановка неразрывных пробелов у тире или единиц измерения), могут работать некорректно, если анализируемые части текста разделены тегами. Например, конструкция
не будет обработана (между $ и 100 не будет вставлен неразрывный пробел), так как типограф не видит их как соседние элементы.$<b>100</b> - "Ремонт" HTML: Библиотека использует
для парсинга, который может "чинить" невалидный HTML (например, закрывать незакрытые теги). Это может привести к неожиданным изменениям в структуре, если исходный код был некорректен. Так же может меняться порядок атрибутов тега.BeautifulSoup
Мы знаем об этих особенностях и работаем над улучшением алгоритмов для более точной обработки сложных случаев.
P.S.
Если вам нравится этот проект, можете поддержать отправив любую сумму на мой Т-банк
по ссылке или, для приверженцев децентрализованного будущего,
через Toncoin (TON) (адрес кошелька )
Credits
Разработка: Проект разработан Sergei Erjemin при активном участии различных LLM в роли pair-programmer.