Страх и ненависть к HiDPI

Когда пиксель перестал быть пикселем

Пролог

Looks like 2560 × 1440 — самая недооценённая надпись в macOS. Вы выбираете разрешение монитора, а Apple честно говорит: нет, вы выбираете внешний вид. Сколько места на рабочем столе, какого размера иконки, какой кегль текста. Не то, сколько пикселей задействует GPU и не то, что светится на матрице.

На 27″ 4K эта разница ощущается особенно остро. Настройки обещают 1440p, скриншот может весить 5K, монитор формально 4K — и всё это одновременно правда.

Дальше — история того, как мы дошли до точки, где одна настройка дисплея означает три разных числа, и почему это касается не только Mac, но и Windows, Linux, телефонов и веба.

Когда всё было просто

Эпоха ЭЛТ-телевизоров и мониторов казалась удивительно прямолинейной. Видеокарта задавала режим — скажем, 640×480 — и операционная система строила интерфейс под эту сетку. Разрешение видеорежима почти напрямую совпадало с рабочей сеткой интерфейса: столько столбцов, столько строк, столько же координат в окнах и кнопках.

Но у кинескопа нет фиксированной пиксельной матрицы, как у LCD. Электронный луч пробегает люминофорное покрытие строка за строкой; «пиксель» — это адресуемая точка растра, а не физическая ячейка с жёсткими границами. При близком рассмотрении видны три люминофорные точки — красная, зелёная, синяя. Плотность задавалась dot pitch — расстоянием между триадами, — а не DPI в современном смысле. Тем не менее для разработчика и дизайнера связь «режим 1024×768 = интерфейс на 1024×768» была практически абсолютной.

Жидкокристаллические панели, пришедшие на смену в начале 2000-х, изменили правила. У LCD фиксированная решётка ячеек: родное разрешение — единственный режим без потерь, все остальные требуют интерполяции. Пиксель впервые стал физической константой стекла, а не договорённостью между видеокартой и лучом.

Стандартные режимы складывались постепенно: 640×480, 800×600, 1024×768, 1280×1024. Каждый новый шаг давал заметный прирост рабочего пространства. Дизайнер открывал Photoshop, создавал макет 1024×768 и был уверен: именно столько пикселей увидит пользователь. Ни больше, ни меньше.

Windows 95, 98, 2000, XP формально знали про DPI — dots per inch, точек на дюйм. В системе существовала настройка, шрифты и диалоги могли масштабироваться. Но практическая культура интерфейсов была пиксельной: массово все жили на 96 DPI, смена значения была редкой и ломала верстку приложений, рассчитанных на фиксированные размеры. Мониторы одного класса имели схожий физический размер и схожее разрешение. 15-дюймовый кинескоп на 1024×768 и 17-дюймовый LCD на 1280×1024 давали примерно одинаковую плотность — около 80–90 точек на дюйм. Интерфейс рисовался в пикселях, и пиксель был единицей измерения.

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

Рождение DPI

Понятие «точек на дюйм» пришло из типографики задолго до компьютеров. Традиционная печать оперировала пунктами — единицами, привязанными к физическому размеру. Классическая типографская логика: 72 пункта в дюйме. PostScript, созданный Adobe и воплощённый в принтере Apple LaserWriter, закрепил эту модель в цифровом мире.

На экранах Microsoft в эпоху Windows выбрала 96 DPI как базовую единицу. Это не физическая плотность монитора — это логическая договорённость: «один дюйм интерфейса соответствует 96 логическим точкам». Реальный монитор мог иметь 80 или 100 физических точек на дюйм, но система рисовала так, будто их 96. Разница была незаметна, пока плотность экранов не начала расти.

Apple шла другим путём. Компания NeXT, которую основал Стив Джобс после ухода из Apple, создала Display PostScript — систему, где экран и принтер говорили на одном языке описания страницы. Векторная графика, шрифты, координаты — всё в абстрактных единицах, не привязанных к конкретному разрешению растра. После возвращения Стива в Apple эта философия перекочевала в Mac OS X через Quartz — движок двумерной графики на основе PDF.

Quartz и Core Graphics изначально проектировались с расчётом на то, что конечное разрешение выходного устройства может быть любым. Рисуете линию толщиной «1 пункт» — система сама решит, сколько физических пикселей ей соответствует на конкретном мониторе. Это казалось избыточным в 2001 году. Через десять лет оказалось пророческим.

Retina — маркетинговое название, которое Apple дала дисплеям с плотностью, при которой отдельная точка перестаёт быть различимой невооружённым глазом на типичном расстоянии просмотра. Порог — примерно 220 физических точек на дюйм при расстоянии около 25–30 см для телефона и около 60 см для ноутбука. Но за маркетингом стояла инженерная идея: плотность экрана выросла настолько, что старые интерфейсы стали бы микроскопическими, если рисовать их один к одному.

Откуда пошёл HiDPI

Идея не родилась в 2010 году с iPhone 4. Её фундамент закладывался десятилетиями: PostScript и пункты в печати, 96 DPI в Windows, Display PostScript и Quartz у Apple. Все эти системы уже отделяли логическую единицу от физического вывода — просто на кинескопах и ранних LCD разница была настолько мала, что её можно было игнорировать.

HiDPI как массовую проблему толкнул именно мобильный рынок — и здесь интуиция не подводит.

Смартфон нельзя бесконечно увеличивать: он должен помещаться в карман и ладонь. Зато пользователь держит его на 30 см от глаз — ближе, чем монитор. Чтобы текст оставался читаемым и картинка выглядела резко, производителям пришлось наращивать плотность пикселей внутри фиксированного физического размера. Первый iPhone (2007) уже имел ~163 PPI — плотнее типичного десктопа того времени. iPhone 4 (2010) удвоил разрешение при том же экране 3,5″: 960×640 физически, 480×320 логически, масштаб 2×. Apple назвала это Retina — и впервые миллионы людей увидели, зачем нужен логический пиксель.

Android пришёл к тому же с другой стороны. С самого начала (2008) Google ввёл dp — density-independent pixels, независимые от плотности пиксели. Базовая линия — mdpi, 160 dpi. Дальше пошли корзины плотности: ldpi (120), hdpi (240), xhdpi (320), xxhdpi (480), xxxhdpi (640). Разработчик описывает кнопку «48 dp шириной» — система сама переводит в физические пиксели в зависимости от экрана. Термина HiDPI Google не использовал, но задача была та же: один интерфейс на сотнях конфигураций.

Мобильный рынок сделал то, что десктоп не мог:

Объём. Миллиарды устройств, миллионы приложений. Каждый разработчик столкнулся с @2x-ассетами, dp и scale factor — раньше, чем большинство веб-мастеров и Windows-программистов.

Полноэкранный интерфейс. На телефоне нет «окна в окне» с фиксированным 96 DPI. Приложение занимает весь экран, и любая ошибка масштаба бросается в глаза.

Физические размеры touch-таргетов. Apple требует минимум 44×44 pt для нажимаемых элементов — не 44 пикселя, а 44 логических точки. На экране 326 PPI это уже 88×88 физических точек. Без разделения logical/physical интерфейс был бы либо микроскопическим, либо нечитаемым.

App Store и Play Market. Централизованная дистрибуция ускорила обновление: через год после Retina значительная доля iOS-приложений уже поставляла @2x-графику. На десктопе legacy-софт сидит годами без обновлений.

Десктоп отставал на два–три года. Retina MacBook Pro — 2012, через два года после iPhone 4. Windows-масштабирование стало терпимым только к Windows 10. Дешёвые 4K-мониторы — середина 2010-х. Настольные ОС унаследовали модель, отработанную на телефонах: backing scale factor в AppKit, devicePixelRatio в браузерах, Per-Monitor DPI в Windows — всё это пришло после того, как мобильные разработчики уже научились жить с @2x.

Так что HiDPI — не «мобильная модель победила десктопную». Скорее: мобильный рынок первым столкнулся с проблемой остро, первым нашёл рабочие абстракции и первым приучил индустрию к логическим единицам. Десктоп подтянулся позже — с тем же baggage legacy-приложений, но с готовым словарём терминов.

Retina изменила всё

До Retina связь была простой: один пиксель приложения — один пиксель экрана. После появления дисплеев с плотностью 220 PPI и выше эта связь разорвалась.

Возьмём iPhone 4: физическое разрешение 960×640 точек, но интерфейс проектировался для логической области 480×320. Каждый «логический» пиксель интерфейса отображался блоком 2×2 физических точек. Масштабный коэффициент — 2×. Иконка 44×44 логических точек занимала 88×88 физических пикселей и выглядела так же по размеру на экране, как 44×44 на старом iPhone — но резче.

Терминология, которую пришлось освоить всем:

Physical Pixel — реальная точка на матрице дисплея. То, что измеряет спецификация монитора.

Device Pixel — то же самое с точки зрения API: физический пиксель устройства вывода.

Logical Pixel (CSS Pixel, Point) — абстрактная единица интерфейса. На Retina-дисплее один логический пиксель может занимать 2×2, 3×3 или больше физических точек.

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

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

iOS и Android

Две доминирующие мобильные платформы решили одну задачу по-разному — и обе стали школой HiDPI для всей индустрии.

iOS

Apple выбрала points (pt) как логическую единицу. Размер экрана в points не меняется при переходе на Retina: iPhone 4 и iPhone 3GS оба 320×480 pt в портрете — но первый 960×640 px, второй 320×480 px. Масштабный коэффициент — scale factor: 1×, 2×, 3×. Сейчас iPhone 15 Pro — 393×852 pt при физических 2556×1179 px, scale factor 3×.

Графика поставляется в наборах: icon.pngicon@2x.pngicon@3x.png. UIImage, SwiftUI и UIKit подбирают нужный файл автоматически. Шрифты и векторные элементы масштабируются через Core Graphics — отдельный растр не нужен.

UIKit сообщает scale через UIScreen.main.scale и traitCollection.displayScale. Auto Layout оперирует points. Dynamic Typeмасштабирует шрифты по системной настройке доступности — ещё один слой поверх HiDPI: пользователь выбирает «крупный текст», и pt растут независимо от плотности матрицы.

Safe Area, notch, Dynamic Island — всё в points. Разработчик рисует отступ 16 pt, система переводит в физические пиксели.

Модель Apple жёсткая и дискретная: 1×, 2×, 3× — целые коэффициенты. Дробного масштаба на iOS практически нет. Это упрощает жизнь: либо попадаешь в целое число, либо нет.

Android

Google выбрал dp (density-independent pixel) и sp (scale-independent pixel для текста). Базовая плотность — mdpi, 160 dpi: на ней 1 dp = 1 px. На hdpi (240 dpi) 1 dp = 1,5 px. На xxhdpi (480 dpi) 1 dp = 3 px. Формула: px = dp × (dpi / 160).

Вместо фиксированных scale factor — density buckets и непрерывный DisplayMetrics.density. Устройство может иметь density 2,625 или 3,5 — не только 2,0 и 3,0. Это гибче, но сложнее: drawable ресурсы кладут в папки drawable-mdpidrawable-hdpidrawable-xhdpidrawable-xxhdpidrawable-xxxhdpi, а система выбирает ближайший и при необходимости масштабирует.

sp для текста учитывает системный множитель шрифта (аналог Dynamic Type). 16 sp текста — 16 dp по плотности экрана, умноженные на пользовательский font scale.

Jetpack Compose и современный Android SDK абстрагируют dp ещё сильнее, но legacy-приложения с hardcoded px до сих пор встречаются — та же боль, что DPI Unaware на Windows.

Две философии

iOSAndroid
Логическая единицаpoint (pt)dp / sp
МасштабДискретный: 1×, 2×, 3×Непрерывный density + buckets
Ассеты@2x@3x в имени файлаПапки по плотности
КонтрольApple задаёт ~20 моделейТысячи конфигураций экранов
Типичная проблемаЗабыли @3x для нового iPhoneНеверный drawable на нестандартной density

iOS — дисциплина через контроль экосистемы. Android — гибкость через абстракцию и ресурсную систему, ценой фрагментации.

Обе платформы приучили миллионы разработчиков к одной мысли: рисуй в логических единицах, система переведёт в физические. Когда те же люди стали делать веб и десктоп, CSS-пиксели и Per-Monitor DPI казались знакомыми — просто с другими названиями.

Иконки: от растра к вектору

HiDPI ударил по иконкам первым — они маленькие, их видно сразу, и на них особенно заметны размытые края.

Эпоха растра

В Windows 95 иконка приложения — это ICO-файл с фиксированными размерами: 16×16, 32×32, иногда 48×48. Один пиксель в макете — один пиксель на экране. Дизайнер рисовал в Photoshop пиксель в пиксель, включая сетку, под конкретное разрешение.

С Retina пришла новая рутина: для каждой иконки — три файла. icon.png (1×), icon@2x.png (2×), icon@3x.png (3×). Кнопка 24×24 pt на iPhone с scale factor 3× требует растр 72×72 px. Забыли @3x — иконка размазывается. Android добавил пять папок плотности — mdpihdpixhdpixxhdpixxxhdpi — и тот же PNG экспортировался в каждую.

Чем выше плотность экранов, тем больше раздувается ассет-пайплайн. Дизайнер тратит время не на форму, а на экспорт. Разработчик следит, чтобы все версии совпали. Любое изменение цвета — правка в полудесятке файлов.

Это работало, пока scale factor был 1×, 2×, 3×. Но дробный масштаб на десктопе (125%, 150%) и нестандартные density на Android показали слабость модели: растровый ассет либо существует в нужном разрешении, либо система интерполирует — и появляется мыло.

Переход к вектору

Выход оказался очевидным: описывать иконку не сеткой точек, а контурами — path, stroke, fill. Один файл на все плотности. Система растеризует его в нужном разрешении в момент отрисовки — ровно так, как Core Text растеризует шрифт.

iOS и macOS — SF Symbols (с 2019 года). Тысячи системных иконок — векторные глифы в шрифтовом формате. Разработчик пишет Image(systemName: "gear") — SwiftUI берёт контур, масштабирует под текущий scale factor, рендерит через Core Graphics. Один символ — любая плотность. В Asset Catalog можно класть PDF-векторы: Xcode генерирует растр на лету для 1×, 2×, 3×, но исходник один.

Android — Vector Drawable. XML-файл с path-данными, доступен с API 21. <vector android:width="24dp" android:height="24dp"> — иконка в dp, не в px. Material Icons поставляются как vector drawable. Compose рисует Icon(Icons.Default.Settings) из векторного описания.

Windows 11 — Segoe Fluent Icons. Шрифт с иконками-глифами, аналогично SF Symbols. Системные элементы интерфейса — векторные. Старые .ico в legacy-приложениях остаются растровыми — отсюда контраст «новый Settings чёткий, старый диалог мыльный».

Веб — SVG. Icon fonts (Font Awesome, Material Icons as webfont) были промежуточным шагом: один шрифт, любой размер, но проблемы с antialiasing и доступностью. SVG в <img>, inline в HTML или через React/Vue-компоненты — нынешний стандарт. width: 24px в CSS — логический размер; браузер растеризует SVG в физическое разрешение с учётом devicePixelRatio.

Figma, Sketch экспортируют иконки как SVG по умолчанию. Растровый PNG — опция для фотографий, не для UI-графики.

Что изменилось по сути

Векторная иконка не отменяет растеризацию. GPU по-прежнему получает bitmap — просто bitmap создаётся последним шагом, уже в разрешении конкретного экрана. Разница в том, что разработчик и дизайнер больше не выбирают, сколько пикселей нарисовать. Они задают форму в логических единицах — dp, pt, CSS px — а плотность становится проблемой рендерера, не проблемой ассет-пайплайна.

Отсюда парадокс: HiDPI сначала размножил растровые файлы (@2x, @3x, пять папок density), а потом убилнеобходимость в них для иконок и простой UI-графики. Шрифты прошли тот же путь раньше — TrueType не требует отдельного файла на каждый PPI. Иконки догнали.

Растр никуда не делся полностью: фотографии, скриншоты, текстуры в играх, favicon.ico в закладках браузера, legacy-приложения с bitmap-иконками. Но для системного интерфейса вектор стал нормой — и это ещё одно доказательство, что пиксель перестал быть единицей проектирования, даже если остался единицей вывода.

Как работает современный стек отображения

Путь от нажатия кнопки «Нарисовать» до свечения матрицы длиннее, чем кажется:

Приложение описывает интерфейс: положение окон, текст, векторные примитивы. На этом уровне координаты обычно логические.

GUI Toolkit переводит описание в команды отрисовки. Qt и GTK знают о масштабе дисплея и умножают размеры на коэффициент. Старый Win32-код может этого не знать — отсюда проблемы совместимости.

Compositor собирает все окна в единый кадр. На macOS это Core Animation — каждый слой может быть трансформирован, размыт, анимирован аппаратно. На Linux с GNOME — Mutter. На Windows — Desktop Window Manager (DWM). Композитор работает с буферами в разрешении, которое определяет система, а не приложение.

GPU выполняет растеризацию: превращает векторы и текст в bitmap нужного размера. Metal на Apple, Vulkan/OpenGL на Linux и Windows.

Display Engine — часть драйвера и контроллера монитора — отправляет готовый кадр на панель по протоколу DisplayPort или HDMI.

На macOS стек выглядит так: AppKit → Core Animation → Metal → IOGraphics. Quartz 2D рисует векторную графику, Core Text — глифы, Core Animation управляет слоями, Metal выполняет финальную отрисовку.

На Linux исторически доминировал X11 — протокол, созданный в 1984 году для сетевых терминалов. X11 не знал о HiDPI: координаты были пикселями серверного framebuffer’а. XRandR позволял менять разрешение, Xft — рендерить сглаженные шрифты, но единой модели масштабирования не существовало. Wayland, пришедший на смену, изначально проектировался с учётом per-output scale factor.

Windows DWM появился в Vista и стал обязательным с Windows 8. Он рисует каждое окно в offscreen-буфере и композитит их с учётом DPI-настроек монитора. Per-Monitor DPI Awareness — относительно позднее дополнение, без которого смешанные конфигурации (4K + FullHD) превращались в кошмар.

Почему 4K оказался неудобным

Не все 4K-мониторы одинаковы. Дело не в маркетинговой цифре «3840×2160», а в том, как эта цифра соотносится с диагональю экрана.

Посчитаем PPI — физических точек на дюйм. Сначала конфигурации, с которых всё начиналось, затем современные:

МониторРазрешениеДиагональPPI
14″640×48014″~57
15″800×60015″~67
15″1024×76815″~85
17″1024×76817″~75
17″1280×102417″~96
19″1280×102419″~86
20″1600×120020″~100
22″1680×105022″~90
23″1920×108023″~96
24″1920×108024″~92
27″2560×144027″~109
27″3840×216027″~163
27″5120×288027″~218
32″3840×216032″~138

Обратите внимание на закономерность. Долгие годы большинство мониторов жило в диапазоне 75–100 PPI: 15″ на 1024×768, 17″ на 1280×1024, 20″ на 1600×1200. Дизайнер, верстающий под 1024×768, автоматически попадал в эту плотность — отсюда и ощущение, что «пиксель был пикселем». 24″ Full HD и 27″ 1440p продолжили традицию: ~90–110 PPI. 27″ 5K — около 218 PPI. 32″ 4K — около 138 PPI. Эти конфигурации «сели» на рынок не случайно: они попадают в комфортные диапазоны или, в случае 5K, компенсируют плотность целочисленным масштабом.

Apple выбрала для Retina MacBook и iMac порог ~220 PPI физически, что при масштабе 2× даёт ~110 логических PPI — ровно столько, сколько у 27″ 1440p-монитора. Studio Display — 27″, 5120×2880, масштаб 2×, логически 2560×1440 при ~109 PPI. Пользователь переходит с обычного 1440p-монитора и не замечает разницы в размерах элементов — только в резкости.

27″ 4K — ~163 PPI — попадает в мёртвую зону. Слишком плотно для 100% масштаба: текст и иконки мельче, чем привыкли пользователи 1440p. Слишком редко для чистого 2×: коэффициент 1.5× даёт логическое разрешение 2560×1440, но полтора физических пикселя на логический — дробное масштабирование. Линии толщиной 1 логический пиксель рисуются то в 1, то в 2 физических точки. Текст выглядит чуть размытым. На Windows и Linux это особенно заметно; macOS справляется лучше за счёт качественного grayscale antialiasing, Core Text, Core Animation и общего контроля стека — но компромисс остаётся.

32″ 4K при 100% масштабе даёт ~138 PPI — ближе к комфортному диапазону. Элементы крупнее, чем на 27″ 4K, дробное масштабирование часто не нужно. Именно поэтому 32″ 4K воспринимается естественнее, хотя маркетинговая цифра та же.

Угловой размер элемента зависит и от PPI, и от расстояния до глаз. Монитор на 80 см — и 163 PPI уже не кажется мелким. Но большинство ставит 27″ монитор ближе, и математика работает против 4K на этой диагонали.

Почему текст кажется мелким, даже когда он резкий

Здесь путают две разные вещи: резкость и размер.

Резкость — насколько чётко прорисованы контуры глифов и линий. На 27″ 4K при 100% масштабе текст может быть кристально резким: каждый штрих занимает достаточно физических пикселей, antialiasing работает на высокой плотности. Но при этом буквы физически малы — их высота в миллиметрах меньше, чем на 27″ 1440p при том же системном размере шрифта.

Размер текста в интерфейсе задаётся не PPI монитора напрямую, а логическими единицами: пунктами, CSS-пикселями, системным масштабом. Шрифт 13 pt на 27″ 1440p и 13 pt на 27″ 4K при 100% — это одинаковые логические 13 pt, но разный физический размер на стекле. На 4K в режиме без масштабирования те же 13 pt займут меньше миллиметров по высоте.

Важна не только метрика «pt», но и x-height — высота строчных букв в конкретном шрифте. San Francisco, Segoe UI и Inter при одинаковом кегле выглядят по-разному: разная высота «а» и «e», разная ширина, разная плотность. Дизайнер, привыкший к одному шрифту на 109 PPI, на 163 PPI получит другой визуальный ритм — даже если система сообщает тот же размер.

Расстояние до глаз — третий множитель. Телефон держат на 30 см, ноутбук — на 50, настольный монитор — на 60–70. Угловой размер объекта = физический размер / расстояние. Монитор дальше — элементы кажутся меньше при той же физической высоте. Пользователь, отодвинувший 27″ 4K подальше, часто говорит «нормально»; тот, кто сидит близко, — «мелко».

Плотность интерфейса — четвёртый слой. macOS «Looks like 2560×1440», Windows 150%, GNOME fractional 150% — всё это увеличивает логические элементы, жертвуя частью рабочего пространства. Текст становится крупнее не потому, что монитор «исправился», а потому что система нарисовала его в меньшем логическом пространстве и растянула. Резкость при этом может сохраниться — или слегка пострадать от дробного масштаба.

Отсюда типичная жалоба: «Всё чёткое, но читать некомфортно». Это не противоречие. Это сигнал, что проблема не в матрице и не в antialiasing, а в том, что физический размер символов и плотность рабочего стола не совпали с привычками глаз. HiDPI решает резкость. Комфорт чтения — отдельная задача, и она живёт в миллиметрах, а не в пикселях.

Великая ложь настроек дисплея

Откройте System Settings → Displays на Mac с 4K-монитором. Вы видите: «2560 × 1440». Подпись «Looks like» — «Выглядит как». Это не разрешение, в котором работает система. Это логическое разрешение — размер рабочего стола в абстрактных единицах.

Что происходит на самом деле — и здесь важно не смешивать разные конфигурации:

27″ 5K (5120×2880), режим «2560×1440». Чистый 2×. Логическая область 2560×1440, framebuffer 5120×2880 — ровно родное разрешение панели. Один логический пиксель = 2×2 физических. Без дробного масштаба, без даунскейла.

27″ 4K (3840×2160), режим «Looks like 2560×1440». Другая стратегия. macOS для scaled-режимов часто строит увеличенный виртуальный framebuffer — нередко 5120×2880 или близкий к нему — рендерит интерфейс туда с высоким backing scale factor, а затем уменьшает картинку до физических 3840×2160. Логически вы работаете в 2560×1440, физически светится 4K-матрица, а между ними — промежуточный буфер, который больше физического разрешения. Отсюда игра, опрашивающая API напрямую, может показать 5120×2880 на мониторе, который формально 4K.

Windows и Linux используют свои схемы: DWM на 150% обычно композитит в родном 3840×2160 с дробным масштабом элементов; GNOME/KDE могут рендерить в 2× и уменьшать до 1.5×. Стратегии разные, путаница одинаковая.

Общая схема для любой ОС:

  1. Система задаёт логическое разрешение — «сколько места на рабочем столе».
  2. Приложения рисуют интерфейс в логических координатах.
  3. Compositor и GPU формируют framebuffer — его размер может совпадать с физическим, превышать его или быть промежуточным.
  4. Игра или полноэкранное приложение, обращаясь к Metal, Vulkan или DirectX напрямую, видит не логическое разрешение, а то, что сообщает драйвер и API — часто физическое или виртуальное framebuffer-разрешение.

Пользователь думает: «У меня монитор 4K, я выбрал 1440p, игра должна рендерить в 1440p». Реальность: три разных числа — логическое, framebuffer, физическое — и три разных контекста их использования.

На Windows картина похожая, но терминология другая: рекомендуемые 150% на 27″ 4K означают логическую область ~2560×1440, а DWM всё равно композитит в родном разрешении дисплея.

Проверить реальность можно утилитами вроде Screenshot (смотреть размер захваченного изображения), system_profiler SPDisplaysDataType на macOS или xrandr --verbose на Linux. Цифры часто удивляют.

Самый бытовой способ на macOS — сделать скриншот экрана (⌘⇧3) и открыть «Информацию» у файла. На 27″ 4K в режиме «Looks like 2560×1440» PNG может оказаться 5120×2880 — не потому что монитор 5K, а потому что macOS сохраняет backing framebuffer, в котором рендерился интерфейс. Скриншот показывает не физическую матрицу, а то, что система нарисовала перед даунскейлом. Удобная ловушка для любопытного пользователя и прямое доказательство разрыва между «как выглядит» и «как светится».

Apple

Apple прошла путь HiDPI раньше и последовательнее остальных — не потому, что инженеры умнее, а потому, что контролировала весь стек: железо, ОС, SDK, типовые приложения.

Quartz изначально векторный. Core Animation добавил аппаратно ускоренные слои с трансформациями — масштабирование стало дешёвой операцией. Metal заменил OpenGL как низкоуровневый API и дал предсказуемую производительность при рендеринге Retina framebuffer’ов.

Retina на macOS работает через backing scale factor. Каждый NSWindow и NSView знает свой backingScaleFactor — 1.0, 2.0, иногда промежуточные значения. AppKit автоматически создаёт bitmap в @2x разрешении для @1x логических координат. Разработчик, следуя Human Interface Guidelines, поставляет ассеты в двух разрешениях: icon.png и icon@2x.png.

Studio Display — 27″, 5120×2880 — не случайность. Это ровно удвоение 2560×1440. Масштаб 2× — целочисленный. Каждый логический пиксель — ровно 2×2 физических. Никакого дробного масштабирования, никакого мыла. Apple никогда не выпускала 27″ 4K-монитор, потому что 163 PPI не делится на 2× с комфортным логическим PPI. 5K — единственный вариант, который сохраняет целочисленный масштаб при привычной плотности интерфейса.

Масштабирование на macOS почти незаметно не по волшебству, а по дисциплине: целочисленные коэффициенты на 5K, ассеты @2x/@3x, качественный grayscale antialiasing через Core Text, аппаратные слои Core Animation, годы доработки пограничных случаев. На 4K-мониторах в scaled-режимах macOS компенсирует дробность увеличенным виртуальным framebuffer’ом — это другой, но тоже инженерный компромисс. Это не значит, что проблем нет — Electron-приложения, старый OpenGL-код и игры по-прежнему спотыкаются — но базовый уровень высокий.

Linux

Linux получил HiDPI позже и болезненнее. Причина — X11.

X Window System создавался для эпохи, когда один мощный Unix-сервер обслуживал десяток терминалов с одинаковыми мониторами. Протокол передаёт примитивы: «нарисуй линию от (100, 200) до (300, 400)». Координаты — пиксели. Если сервер работает в 1920×1080, все клиенты рисуют в 1920×1080. Масштабирование? Каждое приложение масштабирует себя само — а большинство не умеет.

Xft добавил сглаженные шрифты. XRandR — смену разрешения и работу с несколькими мониторами. Но единого DPI-aware стека не было. Пользователь 4K-монитора в 2014 году видел микроскопические окна GTK2-приложений и гигантские курсоры в старых Qt4-программах.

GTK3 и Qt5 добавили поддержку GdkWindow scale factor и QT_SCALE_FACTOR. Wayland-native приложения получают scale от compositor’а через протокол wl_output. Но переходный период длится годами: XWayland запускает X11-приложения внутри Wayland-сессии, и здесь начинается мыло.

XWayland рисует X11-клиент в буфере без учёта scale, после чего compositor масштабирует bitmap. Bitmap, масштабированный вверх, не становится резче — он становится крупнее и размытее. Часть Electron-, Java-, Wine- и legacy-приложений до сих пор идёт через XWayland на GNOME/KDE, даже если Firefox или IntelliJ уже умеют Wayland-native. Результат знаком каждому пользователю Linux на 4K: одни окна кристально чёткие, другие — как увеличенный скриншот.

Fractional scaling — коэффициенты 125%, 150%, 175% — долгое время были экспериментом. GNOME 42 требовал включать его через экспериментальный флаг и мириться с двойным буфером (рендер в 2×, уменьшение до 1.5×). GNOME 45–46 улучшили ситуацию; GNOME 50 (2025) сделал fractional scaling заметно стабильнее — но разрыв между версиями дистрибутивов означает, что опыт пользователя Ubuntu 22.04 и Fedora 42 радикально отличается.

KDE Plasma исторически справлялся лучше со смешанными конфигурациями мониторов, но со своими особенностями. Sway и другие compositor’ы на базе wlroots дают контроль, но требуют ручной настройки.

Linux и HiDPI — история постепенного вымирания X11. Каждый год становится лучше. Каждый год пользователи 27″ 4K находят новый пограничный случай.

Windows

Microsoft заложила 96 DPI в Windows на заре и не могла изменить это без поломки миллионов приложений. Базовый размер шрифта, отступы диалогов, размеры иконок — всё калибровалось под 96 логических точек на дюйм на типичном мониторе.

Когда появились первые высокоплотные дисплеи для ноутбуков, Windows 7 добавила масштабирование — 125%, 150%. Работало плохо: приложения получали bitmap, растянутый билинейной интерполяцией, и выглядели мыльно.

Windows 8.1 принесла Per-Monitor DPI. Windows 10 доработала. Существует три класса приложений:

DPI Unaware — приложение не знает о масштабировании. Windows рисует его в 96 DPI и bitmap-масштабирует. Результат: размытые окна, но хотя бы нормального размера.

System DPI Aware — приложение знает DPI основного монитора при запуске. Перетащили окно на второй монитор с другим DPI — артефакты.

Per-Monitor DPI Aware (V2) — приложение реагирует на смену DPI в runtime. Это современный стандарт, но legacy-софт (и много корпоративных приложений) до сих пор DPI Unaware.

125%, 150%, 175% — дробные коэффициенты относительно базы 96 DPI. 150% = эффективные 144 DPI. На 27″ 4K это даёт логическую область около 2560×1440 — та же «мёртвая зона», что и на macOS, но без целочисленного 2× Apple на 5K.

Старые программы становятся мыльными не из злого умысла Microsoft, а потому, что их код содержит жёстко заданные размеры в пикселях, bitmap-иконки без векторных версий и предположения о 96 DPI. Windows делает bitmap upscale, потому что приложение не предоставило данных для правильного рендеринга.

DirectWrite и Direct2D — современные API — изначально проектировались с учётом HiDPI. Visual Studio, Office, Edge — чёткие. Старый десктопный софт — лотерея.

Почему веб-разработчики уже не думают пикселями

Веб прошёл параллельный путь — и пришёл к похожему выводу раньше десктопных экосистем.

Табличная вёрстка фиксировала ширину в пикселях: 800px, 1024px. 960 Grid System стандартизировал 960px как «безопасную» ширину для мониторов 1024×768 с учётом scrollbar. Дизайнер знал: макет 960px влезет везде.

Bootstrap и responsive design сломали эту модель. width: 100%max-width, media queries по ширине viewport — не физической, а логической. CSS Pixel определён спецификацией как 1/96 дюйма углового размера, не как физическая точка экрана. На Retina-дисплее 1px border может занимать 2 физических точки — и это нормально.

window.devicePixelRatio сообщает соотношение физических и CSS-пикселей. Значение 2 на Retina Mac означает: CSS-область 800×600 соответствует 1600×1200 физических точек. JavaScript, рисующий на <canvas>, должен учитывать это явно — иначе графика будет размытой.

Container Queries (2023+) сдвинули responsive ещё дальше: элемент реагирует на размер своего контейнера, а не экрана. Пиксель экрана перестал быть значимой единицей для layout.

Figma рисует в логических единицах. Экспорт @1x и @2x — convention, не requirement. Auto Layout, constraints, проценты — всё абстрактно относительно frame, не монитора.

Веб-разработчик, который сегодня пишет width: 375px для mobile breakpoint, имеет в виду CSS-пиксели — логические, привязанные к reference viewport, а не к физической матрице телефона. iPhone 15 Pro имеет физическое разрешение 2556×1179, но CSS viewport — 393×852. Коэффициент ~3×. Тот же принцип, что Retina на desktop, но веб-сообщество усвоило его через media queries и devicePixelRatio, а не через @2x assets.

Будущее

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

Vision Pro и spatial computing вводят points in space — элементы интерфейса привязаны к угловому размеру в поле зрения, а не к resolution панели. Рендеринг выполняется с foveated rendering: максимальная детализация там, куда смотрит глаз. «Разрешение дисплея» теряет смысл как характеристика UX.

8K-телевизоры и мониторы уже существуют, но контент и интерфейсы не поспевают. На типичном расстоянии просмотра прирост от 4K к 8K субъективно минимален — как переход от Retina к Super Retina на iPhone.

Складные дисплеи и нестандартные aspect ratio ломают последние assumptions о «стандартном мониторе». Приложение должно адаптироваться к форме, а не к resolution.

Дополненная реальность накладывает интерфейс на мир без фиксированного framebuffer’а. UI-element существует в метрах и градусах, не в px.

Единственная стабильная величина — угловой размер объекта в поле зрения пользователя. Всё остальное — детали реализации конкретного железа.

Практический вывод

Без рейтингов и «лучших мониторов» — только инженерная карта того, что обычно работает:

Конфигурация~PPIТипичный масштабЧто ожидать
24″ 1920×1080~92100%Классический Full HD. Масштабирование не нужно. Привычная плотность, достаточная резкость для офиса.
27″ 2560×1440~109100%Эталонный настольный формат последних лет. Логическое пространство и физический размер элементов сбалансированы.
27″ 3840×2160~163125–150% / «Looks like 2560×1440»Компромисс. На 100% — мелко; на 150% — логически как 1440p, но с дробным или виртуальным масштабированием. Зависит от ОС.
27″ 5120×2880~218200% / «2560×1440»Идеальный 2× в HiDPI-модели, особенно на macOS. Целочисленный масштаб, логически как 1440p, физически вдвое резче.
32″ 3840×2160~138100–125%Крупный практичный 4K. Элементы больше, чем на 27″ 4K; часто обходится без дробного масштаба.

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

Заключение

Мы живём в переходный период. Мониторы продают в физических пикселях. Настройки показывают логическое разрешение. Игры рендерят в framebuffer’е, о котором пользователь не подозревал. Дизайнеры работают в points. Веб — в CSS-пикселях. Windows — в 96-DPI units с процентным масштабом.

Купили 27″ 4K и удивляетесь, почему всё так сложно — вы столкнулись не с плохим монитором, а с дырой в экосистеме между 1440p и 5K. Выбрали «Looks like 2560×1440» и игра показывает 5120×2880 — вы увидели разрыв между логическим, framebuffer и physical resolution. Понимание этого разрыва не сделает масштабирование идеальным, но хотя бы объяснит, почему «просто пиксель» больше не существует как единица проектирования.

Пиксель не умер как физическая единица вывода — GPU по-прежнему пишет в буфер кадра точками матрицы. Но он умер как единица, в которой имеет смысл думать об интерфейсе. Осталось только перестать делать вид, что он ещё жив.