Прикручиваем определение поддержки формата APNG к Modernizr

    Несмотря на то, что все говорят о возможностях HTML5, такой элементарный элемент дизайна сайта как прелоадер с прозрачностью до сих пор приходится делать с использование Animated GIF. Использование 8-битного анимированного GIF не даёт возможности реализовывать полупрозрачные переходы. В качестве современной альтернативы анимированному GIF можно было бы предположить два конкурирующих формата — MNG и APNG, но MNG не имеет и скорее всего уже никогда не получит нативной поддержки со стороны браузеров, а формат APNG мы уже можем использовать в Firefox и Opera ещё со второй половины 2008 года. К сожалению, Chrome, Safari и Internet Explorer, остались в стороне, для них по прежнему придется использовать угловатые картинки в старом формате GIF. Тем не менее, сегодня у нас есть такая замечательная штука как Modernizr — инструмент перехода к практике определения возможностей браузера, вместо использования порочной практики определения наименования и версии браузера.



    Собственно сам APNG Modernizr Test


    После нахождения небольшого кусочка javascript-кода определяющего поддержку APNG, мне как-то сразу захотелось прикрутить его к Modernizr, благо у последнего для этого есть специальное простое API:

    /**
     * APNG Modernizr Test Workaround
     */
    (function(){
        var testImage = new Image();
        var canvasContext = document.createElement('canvas').getContext('2d');
        var isApngSupported = false;
    
        testImage.onload = function () {
            canvasContext.drawImage(testImage, 0, 0);
            isApngSupported = canvasContext.getImageData(0, 0, 1, 1).data[3] === 0;
            if (typeof isApngSupported !== "boolean") {
                var isApngSupported = false;
            }
            Modernizr.addTest('apng', function() {
                return isApngSupported;
            });
        };
        testImage.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";
    })();
    


    В зависимости от того поддерживает ли браузер APNG или нет, у тега html появится дополнительный класс apng или no-apng. Из CSS мы можем это использовать так:

    .no-apng .preloader {
        background-image: url(some.gif);
    }
    .apng .preloader {
        background-image: url(some.png); 
    }
    


    Программами, не понимающими анимацию, APNG отображается как статичный PNG.

    За эту информацию спасибо моему коллеге SeVit`у.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 26

      –1
      Эх, думал что тут хак чтоб APNG и в хроме показывался нормально :( Но все равно полезная штука :)
      +1
      Как я понимаю, вся сила в строке isApngSupported = canvasContext.getImageData(0, 0, 1, 1).data[3] === 0; Разъяснили бы кратко, что там к чему.
        0
        Эли Грей сам не расписывает свой метод,
        как я понял «вся сила» в анимированной картинке завёрнутой в dataUri.
        Могу только предположить, что drawImage размещает в canvas последний, а не первый, кадр из анимированной картинки.
        Главное же, что CanvasPixelArray возвращаются разные, для анимированной и неанимированной картинок.

        Добавил ссылку на автора кода.
          +3
          Просто догадаться. Я когда увидел заголовок сразу придумал как бы я это сделал.

          В Data URI находится APNG с двумя кадрами, которые меняются без задержки и не закальцованы. В браузерах с поддержкой APNG будет виден последний кадр, без оной — первый. Кадры 1×1 пиксель и различаются одной цветовой компонентой. Её и проверяем.
          0
          Не, логика такая: canvasContext.getImageData(0, 0, 1, 1) возвращает объект ImageData для левого верхнего пикселя canvas. ImageData же содержит объект data типа CanvasPixelArray (по факту это массив Uint8ClampedArray), размерностью height × width × 4 (4 байта на пиксель, ибо RGBA). Ну и судя по data[3], смотрим на Alpha-компонент это одинокого пикселя.
            0
            Вообще-то все браузеры поддерживают первый кадр APNG, тк он обратно совместим с обычным PNG. Вопрос в том, почему в браузерах, которые поддерживают APNG отрисовывается другой кадр,
              0
              Потому что там конечная анимация из двух кадров.
                0
                А! Совсем забыл. В APNG есть такая фишка — первый кадр можно совсем не использовать, а браузеры, понимающие только PNG, будут использовать только первый кадр.
              +1
              Только одно маленькое замечание: Этот скрипт проверяет не «поддержку поддержку APNG» а «поддержку поддержку Canvas API + Data protocol + APNG „
                0
                К сожалению, более удобного способа без использования canvas и data Uri я не знаю.
                  0
                  Ну как же? Есть же ещё «порочная практика определения наименования и версии браузера».
                    0
                    Нууу. Все браузеры, которые не поддерживают Canvas — не поддерживают APNG ;)
                      0
                      Чем полагаться на такие вещи лучше, чем полагаться на версии браузеров? Практически то же самое выходит.
                        0
                        Тем, что если в новой версии Хрома добавится возможность проигрывать APNG — будем использовать нативную реализацию.
                          0
                          И то верно. Но не было бы разумней сначала отсеивать уже заведомо поддерживающие APNG браузеры, не заставляя их выполнять лишний код, и уже потом прогонять тест на остальных?
                            0
                            оно выполняется один раз за 0.1 микросекунды. Если отсеем «уже заведомо поддерживающие APNG браузеры», то в них будет выполнятся за 0.08 микросекунды, а в остальных — за 0.14 микросекунды. Думаете, имеет смысл?
                              0
                              Правда? Есть замеры? Как-то не верится. По-моему, Javascript вообще работает скорее в масштабах миллисекунд, чем микросекунд. Да вот и профилирование Firebug’ом на тестовой странице рапортует мне о 1,5 миллисекунд.

                              Да, тоже очень немного. Но я бы для очистки совести попробовал добавить предварительную фильтрацию и сравнить.
                  +1
                  Надо было добавить «Анимация APNG с помощью canvas в Google Chrome, Internet Explorer 9, Apple Safari»
                  apng-canvas demo

                  Спасибо, однозначно в закладки.
                    0
                    забыл про не отражённую визуально невозможность оставлять ссылки недостойными,
                    вот ссылка на apng-canvas demo
                    davidmz.github.com/apng-canvas/
                      0
                      Ну да. Только в браузерах, где есть Canvas. Это вполне логично, что в браузерах, где нету Canvas нельзя сделать анимацию с помощью Canvas.

                      Тем не менее, это замечательно, т.к. уже все современные браузеры могут поддерживать apng.
                    +1
                    isApngSupported = canvasContext.getImageData(0, 0, 1, 1).data[3] === 0;
                    if (typeof isApngSupported !== "boolean") {
                        var isApngSupported = false;
                    }
                    

                    А какой тип кроме «boolean» может вернуть операция "==="
                      0
                      На будущее: полупрозрачный лоадер можно сделать с помощью сдвига PNG-спрайта джаваскриптом, даже красивее будет
                        0
                        мало того — анимированный гиф можно сохранять с альфа-прозрачностью, что полностью решает проблему.
                          0
                          Интересно. Как это сделать и где это работает?

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

                      Самое читаемое