Почему одна этикетка 80×80 мм печаталась на двух страницах?

Обычная кнопка скачивания выявила одну связанную задачу на стыке бизнес-идентификатора, имён файлов, браузерной пагинации и физических размеров; этикетку не уменьшали — изолировали документ для печати.

Всё началось с небольшого запроса: кнопка «Скачать PNG» в редакторе этикеток должна была открывать настоящий диалог Save As. После нажатия пользователь должен был увидеть понятное имя, выбрать место сохранения и получить файл, который можно опознать, не открывая.

Первая же версия имени выявила более глубокую проблему. Она использовала внутренний SKU вроде SKU-001, хотя на самой этикетке люди видели и использовали Batch No: 30267-0914. Скачивание работало, но семантика данных была неверной: система выбрала технически существующий, но бесполезный в работе идентификатор.

Адрес в Production
/tools/label/
Бизнес-идентификатор в имени файла
Видимый Batch No, если он задан
Пример
30267-0914-BQ.png · 30267-0914-BQ.pdf
Физический размер
Без масштабирования; 80×80 мм остаются 80×80 мм
Проверка пагинации
Шесть размеров дали по одной странице в Chromium

Имя файла — часть модели данных

Правильным решением была не ещё одна функция именования специально для скачивания. Имя файла и видимое поле Batch No теперь берут значение из одного canonical-источника. Если на этикетке стоит 30267-0914, для PNG предлагается 30267-0914-BQ.png, а для PDF — 30267-0914-BQ.pdf. Если эти значения расходятся, как минимум одно из них уже не описывает партию, которую видит пользователь.

Для PDF действует тот же принцип, но интерфейс браузера устроен иначе. В macOS при переходе из браузерной печати к Print → Save as PDF предлагаемое имя PDF берётся из заголовка печатаемого документа. Поэтому перед печатью document.title ненадолго заменяется на имя из Batch No, а после завершения, отмены или возврата управления окну обычный заголовок надёжно восстанавливается. Это не смена SEO-заголовка, а ограниченное состояние с явными границами одного сеанса печати.

Одна страница превратилась в одну страницу и пустой лист

Когда имена стали согласованными, проявился более интересный дефект: этикетка 80×80 мм давала в предпросмотре две страницы, причём вторая была пустой.

Кажется очевидным, что лист 80×80 мм должен помещаться на странице 80×80 мм. Но движок браузера не сравнивает два целых значения в миллиметрах. CSS-миллиметры превращаются в CSS-пиксели, а печатный конвейер ещё раз переводит их в единицы устройства и пагинации. На границе страницы субпиксельное округление, стандартный строчный блок или небольшой вклад body могут вытолкнуть математически «точный» край в следующий pagination fragment.

Исходный print sheet имел размеры страницы, но всё ещё участвовал в обычной пагинации документа. Скрыть только #root было недостаточно: такой подход предполагал, что ни один другой дочерний элемент body не повлияет на печатную раскладку. Для точной границы страницы эта гарантия слишком слабая.

Исправляем пагинацию, а не размер этикетки

Правильное исправление изолирует print sheet от обычного потока пагинации. Печатные стили строго убирают все непечатные дочерние элементы body, обнуляют margin, padding и вклад строчного блока у html и body, а единственный печатаемый лист абсолютно позиционируют в начале страницы. Точное динамическое правило по текущей этикетке сохраняется:

@page { size: <width-mm> <height-mm>; margin: 0; }

Мы намеренно не использовали масштаб 99%, не вычитали по 1 мм из каждой стороны и не переносили этикетку на A4 с опцией «вписать в страницу». Такие приёмы могли бы убрать пустой лист, но одновременно нарушили бы главный контрак вывода. Этикетка 80×80 мм должна физически оставаться 80×80 мм.

Редактор и предпросмотр экспорта можно увеличить до 150%, чтобы с ними было удобнее работать, но это только способ показа. Canonical geometry и число пикселей не меняются: 100×100 мм по-прежнему экспортируются как 1000×1000 px, а 70×20 мм — как 700×200 px. Больший вид на экране не означает больший размер на бумаге.

Как отличить исправление пагинации от удачного исключения

Проверять только 80×80 мм было нельзя: специальный случай для одного размера легко создаёт убедительную, но хрупкую иллюзию. Проверка пагинации Chromium охватила 70×20, 70×40, 80×60, 80×80 и 100×100 мм, а также нестандартный размер 93×57 мм. Все шесть вариантов дали ровно одну страницу.

Автоматизированная среда не могла напрямую прочитать счётчик страниц в нативном предпросмотре печати macOS. Границу доказательств нужно формулировать точно: автоматика доказала, что печатные документы Chromium во всех шести размерах одностраничны; она не имитировала чтение недоступного значения из нативного UI.

Последний шаг произошёл за пределами браузера. После проверки print hotfix в Production содержимое проверенной ветки было сверено и возвращено в GitHub main, так что source tree и Production tree совпали. Это закрытие не позволит уже исправленной ошибке вернуться при следующем развёртывании из неполного исходного состояния.

«Скачивается» ещё не значит «готово», как и «печатается». Готово — это когда источник данных, имя файла, физические размеры, пагинация и исходники Production согласованы между собой.

WEOUR / BUILD

Примите участие в сборке

Если вы решаете реальные задачи в трансграничной торговле, запасах, складе, фулфилменте или автоматизации — расскажите нам о своей задаче.

Оставить запрос Следите за WEOUR / сообщество — позже