Пол-пикселя?

    По-русски если гуглить «полпикселя», везде какая-то истерика: пиксель не делится, и всё тут. По-английски всё чинно :) например. Полпикселя существует, но браузеры пока плохо их рендерят. Местами реагируют на доли пикселя (например, в параметрах шрифтов), но чаще любят округлять до целого.

    Почему так? Раньше понятно, железо не позволяло прорисовывать «половинки». Сейчас им лень. Но каких-то подвижек можно ожидать: технология Flash уже поддерживает точность до 1/20 пикселя.

    Что такое пиксель?


    По терминологии Google, у слова «пиксель» есть 3 значения:
    1. Элемент матрицы экрана. Например, в LCD-экранах один пиксель — 3 светящихся элемента (RGB).
    2. Device-independent pixel (dip) — масштабированный, «кажущийся» размер пикселя, который на любом экране смотрится одинаково. Тут учитывается типичное расстояние от глаз до девайса.
    3. CSS-пиксель. Например, width: 20px;



    Подробнее о разных определениях Google и W3C
    Итак, по Google:

    1. Hardware pixel — физический пиксель матрицы дисплея (или, скажем, фотоаппарата). Например, в экране iPhone 5 — 640 физических пикселей по ширине.

    2. Device-independent pixel (dip) — пиксели дисплея, приведённые к единому масштабу, чтобы соответствовать примерно одинаковому углу зрения на всех девайсах (с учётом расстояния, на котором мы их держим).

    Определение ниочём, давайте на пальцах.

    Берём монитор (самый обычный, не высокой чёткости):
    — полоска 320 пикселей имеет длину пусть 8 см;
    — на монитор мы обычно смотрим с расстояния, скажем, 50 см.

    Берём iPhone 5:
    — держим всегда ближе, пусть 30 см;
    — полоске 320 device-independent пикселей должен соответствовать тот же угол зрения.
    Значит, полоска в 320 dip имеет длину уже не 8, а 5 см.
    Ну понятно, простая пропорция: 8 : 50 ≈ 5 : 30. Чем больше расстояние, тем крупнее должны быть эти «независимые» пиксели, чтобы их было видно так же.

    Для примера iPhone 5 считается, что ширина экрана (около 5 см) — как раз 320 dip.

    Если это 40-дюймовое информационное табло на вокзале, на которое смотрят с расстояния 7 метров, то… сами посчитайте, сколько там dip'ов. :)

    3. CSS pixel — единица измерения вёрстки. Если написано "width: 20px" — это ширина 20 CSS-пикселей.

    По W3C, 1px = 1/96 дюйма или примерно 0,26 мм. Но на W3C всем пофиг (причём пофигизм начался даже до появления W3C), поэтому браузеры всегда тупо считали, что CSS-пиксель равен экранному пикселю при масштабе 100%. Но когда пришли экраны высокой чёткости, они осознали всю ж... неправильность такого подхода. И теперь верстальщику невозможно обяснить, как это — полпикселя!

    UPD: меня поправляют в комментах. Есть уже две версии определения понятия '1px' в стандарте от W3C. Поэтому я рад, что сразу взял за основу терминологию гугла. :)

    В общем, гугл предлагает формулу:

    Scale = CSS_pixels / dip
    Scale — масштаб страницы
    CSS_pixels — число CSS-пикселей на некотором отрезке (например, ширина блока)
    dip — число условных device-independent pixels на этом же отрезке

    Надо это пояснять дальше?


    Суть в том, что:
    1) экранные пиксели и CSS-пиксели могут не совпадать;
    2) связь между ними зависит от многих вещей.

    Бывает ли полпикселя?


    Из сказанного понятно:
    • половина CSS-пикселя — бывает;
    • половина экранного пикселя — не бывает.

    Но браузеры поступают, как им проще:


    <!DOCTYPE html>
    <html>
    <style type="text/css">
    div {
        height: 7px;
        font-size: 7px;
        margin: 1px 0;
        text-align: center;
    }
    </style>
    <body>
    
    <div style="background-color: lightgreen;  width: 20px;">20</div>
    <div style="background-color: deepskyblue; width: 20.5px;">?</div>
    <div style="background-color: lightgreen;  width: 21px;">21</div>
    
    </body>
    </html>
    



    Выводы


    Объявляется конкурс на какие-нибудь практические выводы из этой статьи. Подведение итогов — 1 апреля.

    Share post

    Comments 52

      +16
      Жесточайший батхерт можно получить при рисовании на Canvas. Необходимо указывать сдвиг в пол пикселя для получения прямой толщиной в пиксель (подробнее на stackoverflow).

      Тема еще не раскрыта, но Ваш пост на верном пути!
      • UFO just landed and posted this here
          0
          Да зачем далеко ходить, при обычном transition opacity двигается на пиксель )
            0
            Можно и еще ближе взять — при обычном hover-е на каком-нибудь элементе вся страница в хроме на полпикселя сдвигается.
              0
              Я про хром даже молчу, там всё живёт своей жизнью.
          0
          Помнится, я для этого извращался со scale.

          А если рисовать изображения в дробных пикселях, эффект немного другой.
            +1
            В SVG та же фигня, если хочется попасть в пиксели. А ещё SVG по умолчанию центрируются, и если картинка имеет нечётную ширину, а вписана она в элемент с чётной шириной (или наоборот), то изображение будет смещено на полпикселя.
              0
              Такое же в Direct3D.
              +1
              Полпикселя, а то и меньше — отличное решение для анти-алисинга или даже «antry-grain». Так что рекомендую курить немного www.antigrain.com/ до наступления эффекта.
              • UFO just landed and posted this here
                  0
                  Ещё такой нюанс, вот в iPhone 6+ идёт даунсэмплинг из 2208*1242 в 1920*1080, то есть там вообще, как я понимаю, нельзя сделать рендеринг пиксель-в-пиксель никак?
                  Глянул на симуляторе, действительно, при viewport "width=device-width" края чёткие, CSS не знает про даунсэмплинг. На девайсе будет «размыто».

                  Кстати, только сейчас увидел, что (при других viewport) Safari на iOS ведёт себя как «идеальный браузер на неидеальном мониторе». Интересно, как обстоят дела в Android.
                    0
                    А вы пробовали, действительно ощущение размытости? Говорят, что там dpi такой, что уже реально не различить пикселей и размытость не отличить от ровной линии. На 4S я пиксели прекрасно вижу, этот нестандартный даунсэмплинг стал основной причиной отказа от апгрейда телефона на 6S. Вроде всем хорош, но великоват экран и совершенно неожиданный даунсэмплинг.
                      0
                      Не на чем попробовать. Надеюсь, кто-нибудь отпишет.

                      Я тоже вижу пиксели на 4S, а у 6+ размер пикселя уменьшился всего в 1.5 раза, поэтому downsampling также беспокоит (в теории).
                        +1
                        Если приглядываться — то видно (особенно на специальных картинках потипу чередующихся черно-белых полос). Видео и игры могут рендериться без даунсемплинга, но когда на экране появляются UI-элементы, то даунсемплинг опять включается.

                        При повседневном использовании не заметно, но зная о такой фигне всегда подсознательно будешь искать артефакты (и само собой, иногда находить).

                        Тут подробнее: www.idownloadblog.com/2014/11/20/iphone-6-downsampling-explained/
                    0
                    Я вот как-то не вижу смысла в создании костылей под все возможные варианты.
                    А я вообще за то, чтобы всегда верстали на максимальных DPI, которые есть в продаже. А уже задача рендер-движков — чтобы всё «смотрелось» на более дешёвых экранах (хотя понятно, что пока они её не выполняют, надо тестировать везде).
                    • UFO just landed and posted this here
                        –1
                        Это была просто агитация за HiDPI мониторы :)

                        Когда брал ноут с 200+ DPI, большая часть сайтов смотрелись ужасно. Спустя 2 года ситуация получше, но тоже, 99% растровой графики (включая даже хабр частично) до сих пор не адаптированы под high-res.

                        Будут сайты красиво смотреться — будет стимул у людей покупать нормальные дисплеи и не портить глаза (последнее субъективно).
                          +3
                          Есть один ма-алюсенький нюанс, который останавливает владельцев сайтов от размещения там растровой графики «повышенной четкости». Особенно для мобильных устройств (на которые, как назло, эти «retina-образные» экраны, в основном, и ставят). И называется он широта пропускания канала. Не знаю, как у вас, а у меня в городе Нижнем Новгороде обычный тариф интернета для «простых смертных» подразумевает 100 мегабайт в день. И качать на нем полноразмерный jpeg-и на пару мегабайт с котиком, чтобы только прочитать анекдот под ним — мягко говоря, несколько непрактично.

                          «Кат» был придуман для того, чтобы не грузить канал юзера лишними данными без его явного согласия. Но даже заголовочная картинка может быть великовата. Да, часто это лечится использованием SVG (которое я лично, например, люто поддерживаю). Но не всегда, увы.
                            0
                            nnovgorod.rt.ru/homeinternet — сплошные безлимиты
                            nn.domru.ru/internet — сплошные безлимиты
                            www.nnov.mts.ru/dom/home_inet/tariffs/nnov/ — аналогично
                            nn.megafon.ru/internet/options/ — трафика больше, чем дают в подмосковье.

                            Такое ощущение, что условия у вас всё-таки не совсем обычные.
                              +1
                              Думаю, речь шла про мобильный интернет рублей так за 200-400.
                                0
                                Совершенно верно думаете. Дома у меня 10 мегабит.
                            • UFO just landed and posted this here
                                0
                                Мы с вами видимо в разных Н.Новгородах живём…
                                  0
                                  Хорошо, я живу в Омске. У меня гиг на телефоне, три на смарте и пять на свистульке, с которой раздается Wi-Fi на три стационара и планшет дочки, плюс гостевые компы клиентов. Я просто вынужден основной серфинг вести с браузеров с отключенными картинками и подгружать их при необходимости вручную. А проводное подключение ко мне в частный дом обойдется на данный момент порядка 15 тысяч и около тысячи в месяц за 8 Мбит. При этом я живу в ж таком месте, где даже 3G зависит от погоды, новосибирские инженеры Пчелайна удивились, что оно у меня вообще бывает. А в километре в сторону все работает. Мне нет смысла брать безлимитные тарифы, поскольку у жены в квартире есть нормальная проводная связь, все тяжелое я качаю там. И поверьте, что подобных мне в стране миллионы.
                                    0
                                    Так, а кто спорит? Я вообще только на НН стриггерил, потому что у нас с оптикой тьфу-тьфу все норм, да и по городу много где LTE есть.

                                    Насчёт частных домов — тестю н живущему в частном доме в одном из городов Нижегородской области недавно предложили провести оптику на всю улицу по 8К на дом, далее по обычным тарифам. И это даже не Нижний Новгород.

                                    Не утверждаю, что по стране у нас все ок, но в крупных региональных центрах уж точно.
                                      +1
                                      Примерно одинаковые по населению и развитию города: Омск и Нижний, но достаточно разные и условия, и тарифы. А есть места, где и наши условия кажутся чуть ли не раем. Оптику у нас предлагают пока в очень немногих точках, да и качество связи в реальности не слишком высокое.
                        +6
                        Половина черно-белого пикселя кодируется половиной бита!
                          +8
                          Простите, а Вы имеете в виду экранные биты или CSS-биты?
                            +4
                            Ну это откуда посмотреть. Когда мы печатаем текст CSS- то получаем CSS-биты. А когда этот CSS рендерится браузером — то из половины CSS-бита полуается половина экранного бита. Есть еще, кстати, клавиатурные половины бита — это если клавишу нажать на половину её хода. Можно даже программы писать полубитами. В одном полубайте восемь полубитов.
                              +1
                              И контрольная половинка. У меня всегда сходится.
                                0
                                Вы наверное имеете ввиду кубиты?
                              +2
                              Шутите… а знаете, какой самый компактный формат сжатия для ч/б сканов? Мой товарищ в институте экспериментально выявил, что самое компактное — сжимать 1-битный bmp RAR-ом (сейчас, возможно, 7-zip лучше). Этот метод не дает выводить полутона, но для текста это обычно не надо.
                                +1
                                Ваш товарищ еще больше удивился бы, если перед RAR-ом применил RLE (желательно эвристический).
                                Насколько помню, это давало степень сжатия выше JPG, без потери избыточности (в цвете).
                                  +1
                                  Если без шуток, то самый компактный формат сжатия черно-белых сканов, это TIFF со сжатием CCITT Group 4 (Fax 4)
                                    0
                                    Так DjVu же…
                                  0
                                  Битых 2 часа читал вашу статью, так и и не понял в чем вопрос)

                                  здесь www.w3.org/Style/Examples/007/units.en.html написано что требование к пикселю быть размером 1\96 дюйма относится ко всей печатной продукции, ни про какакие мониторы речи нету.

                                  здесь msdn.microsoft.com/ru-ru/library/ms537660.aspx написано что размер пикселя зависит от устройства, что совпадает с данными из первой ссылки.Здравый разум тоже подсказывает пиксель в CSS всегда был и есть пикселем на устройстве.Его размер зависит от размера и характеристик устройства и включенного графического режима.

                                  Тоесть пиксель на устройстве это всегда пиксель CSS.Полпикселя можно реализовать используя субпиксели, но их число, и метода доступа к ним — специфично и в css не рассматривается.Вообщем это чит.
                                    +1
                                    здесь www.w3.org/Style/Examples/007/units.en.html написано что требование к пикселю быть размером 1\96 дюйма относится ко всей печатной продукции, ни про какакие мониторы речи нету.

                                    Почему я сразу сослался на терминологию Гугла? В ней всё понятно: есть px (CSS pixel), есть dip, они связаны, это разные вещи.

                                    W3C сами запутались, подменяя одно понятие другим. В одном месте стандарта заявляют, что px является absolute length unit и равен
                                    1px is equal to 1/96th of 1in
                                    — никаких исключений про мониторы тут не вижу.

                                    Но далее по тексту, 1px вдруг начинают рассматривать уже в контексте reference pixel, т.е. device-independent:
                                    For reading at arm's length, 1px thus corresponds to about 0.26 mm (1/96 inch).


                                    Ну а про это я писал в статье, но возражу ещё раз:
                                    Тоесть пиксель на устройстве это всегда пиксель CSS.
                                    У меня пиксель на устройстве (iPhone 4S) равен 0,08 мм.
                                    Но CSS (при viewport "width=device-width") рисует 1px толщиной в 0,16 мм.
                                      0
                                      device-width считается в CSS пикселях. Описанное вами поведение верное.
                                        +2
                                        Вообще-то начинать стоило с модуля CSS Values and Units — www.w3.org/TR/css3-values/#absolute-lengths

                                        «For a CSS device, these dimensions are either anchored (i) by relating the physical units to their physical measurements, or (ii) by relating the pixel unit to the reference pixel. For print media and similar high-resolution devices, the anchor unit should be one of the standard physical units (inches, centimeters, etc). For lower-resolution devices, and devices with unusual viewing distances, it is recommended instead that the anchor unit be the pixel unit. For such devices it is recommended that the pixel unit refer to the whole number of device pixels that best approximates the reference pixel.»

                                        — Для CSS-устройства эти единицы измерения привязаны либо 1) к соответствующей физической величине в её физическом измерении, либо 2) соотношением к референсному пикселю. (Т.н. CSS-пиксель.) Для печатных или иных схожих материалов с высоким разрешением привязка должна быть к стандартной физической величине (дюймы, пиксели, и т. д.) Для устройств с низким разрешением или устройств с _нестандартным расстоянием просмотра__ вместо этого рекомендуется, чтобы единицы измерения были привязаны к пикселю. Желательно, к целому числу пикселей или наилучшему приближению.

                                        «The reference pixel is the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm's length. For a nominal arm's length of 28 inches, the visual angle is therefore about 0.0213 degrees. For reading at arm's length, 1px thus corresponds to about 0.26 mm (1/96 inch).»

                                        Референсный пиксель — это угол зрения одного пикселя на устройстве с плотностью пикселей 96dpi на расстоянии вытянутой руки от читателя. Для номинальной длины руки 71 см угол зрения составляет 0,0213 градуса. Таким образом, 1 пиксель составляет 0,26 мм (1/96 дюйма) при чтении на расстоянии вытянутой руки.

                                        Подытоживая: не для печатных материалов (и их аналогов) всё привязано к размеру референсного пикселя, который рекомендуется выбирать таким образом, чтобы он выглядел как один привычный пиксель на типичном расстоянии просмотра устройства. Но в конечном итоге выбор остаётся за производителем.
                                      • UFO just landed and posted this here
                                        0
                                        del
                                          +1
                                          Так что же выбрать? px или em?
                                            0
                                            Общие советы давать трудно. :) У меня есть один проект для iOS на WebKit. Когда адаптировал под iPhone 6 и 6+, самым простым решением оказалось переделать абсолютно все размеры на em, кроме собственного одного (font size), который задаётся в runtime.
                                              0
                                              rem
                                              –2
                                              Не удержался

                                                0
                                                А еще пол пикселя есть в Photoshop. И они прекрасно укладываются в головах дизайнеров и фотографов))
                                                  0
                                                  В одном бите тысяча миллибит.
                                                    +2
                                                    1024, если точнее.
                                                    –3
                                                    Вывод:
                                                    • верстать резиной;
                                                    • для ограничений использовать EM;
                                                    • убивать магию DPI-багов специальным мета-тегом:
                                                      <meta name="viewport" 
                                                          content="width=device-width, height=device-height,
                                                          initial-scale=1.0, user-scalable=no, maximum-scale=1.0"/>
                                                      


                                                    спойлер
                                                    <сарказм>
                                                    А ещё можно изобрести метод «скрытых» посланий, оставляя шифрованную информацию в полупикселях и делая её визуально-видимой только на некоторых дисплеях.
                                                    </сарказм>
                                                      –1
                                                      практические выводы из этой статьи
                                                      когда появится поддержка
                                                      mediaSource: 'screen'
                                                      во всех браузерах,
                                                      спойлер
                                                      будет еще один isIE флаг
                                                        +2
                                                        Пол-пикселя бывает в Хроме и IE в transform:
                                                          0
                                                          половина экранного пикселя — не бывает.

                                                          стоит уточнить, что если известен порядок субпикселей, то вполне бывает 1/3 и 2/3 экранного пикселя. Для некоторых дисплеев также бывает и 1/4 экранного пикселя.

                                                          Only users with full accounts can post comments. Log in, please.