воскресенье, 10 августа 2008 г.

The Best Way to Embed Flash 9 into XHTML without JavaScript, part I

Я тут совершенно случайно ввязался в масштабное исследование, посвященное внедрению флеша в страницы. Точнее, я просто не подозревал, что вокруг столь небольшой темы написано просто умопомрачительное количество некорректной информации.

Итак, необходимо внедрить Flash 9 (AVM2) и при этом достигнуть баланса со следующим списком требований:

  1. Должно играть до полной загрузки ролика (streaming);
  2. Должна работать коммуникация Flash с браузером, в обе стороны;
  3. Должно работать во всех более-менее заметных браузерах;
  4. Должно работать с типом контента application/xhtml+xml для xhtml;
  5. Нежелательны лишние запросы на сервер;
  6. Категорически нежелательны посторонние визуальные эффекты;
  7. Решение должно быть валидным;
  8. Если плагина нет - должен ставиться, если плагин устарел - должен обновляться;
  9. Очень хотелось бы обойтись без яваскрипта;
  10. Желательна отдача referer при загрузке swf, а то ходят слухи, что иногда не отдается;
  11. Желательна работа при режиме высокой безопасности в IE и при отключенном ActiveX;
  12. Отсутствие глюков - чтобы параметры передавались, прозрачность работала и т.д.;
  13. Семантичность - отсутствие лишних сущностей в коде;
  14. Отсутствие необходимости щелкать для активации в IE и Opera;
  15. При невозможности соблюдения всех вышеперечисленных условий должен соблюдаться принцип graceful degradation.
Изучение темы показало, что используются следующие основные способы внедрения флеша в страницу:
  1. через тег embed;
  2. через тег object;
  3. также можно воспользоваться JS-библиотекой типа SWFObject2;
  4. комбинация вложенных тегов object или object&embed.
Начнем с JS [9]
Честно говоря, смысл использования SWFObject от меня ускользнул. Если не вкладывать никакого дополнительного смысла в море статей о нем, то все речи сводятся к щелчку для активации, невнятному "упрощению интеграции" и "определении версии плеера". Первое быстро становится неактуально, т.к. майкрософт убрал эту необходимость. Второе - простно враньё, ведь процесс только замедляется [5, 9], становится менее надежным [3] и работает не всегда [4, 9]. Третье - тема необычайно сложная и не от SWFObject в ней всё зависит. А нужно, чтобы работало [8].
Поэтому, по возможности, сторонние JS-библиотеки я постараюсь не использовать.

Режим высокой безопасности в IE [11]
В этом случае всё печально - Flash работать не будет. Совсем, как не исхитряйся.
Нюансы в IE:
  1. Embed не работает (работает только noembed), но IE ничего не сообщает и не предлагает. Что плохо. И, кстати, атрибут PLUGINSPAGE в IE не работает [8];
  2. При использовании object IE7 выдает желтую полосу с предупреждение, что ActiveX отключен и ссылку на справку. Что неплохо.
Т.е. [11] из списка требований исключается ввиду нереализуемости.

embed
Это тег старый, на данный момент абсолютно нестандартный, но зато поддерживаемый почти всем чем только можно. Кстати, имеет все шансы реинкарнироваться в html5. Всем хорош, только есть у него несколько родовых травм: сейчас невалиден [7] и, главное, совсем не работает мост JS-to-AVM2 [2] во всех версиях IE. Работает только SetVariable для AVM1. Также есть вышеописанная проблема с [11]. Т.е. применение этого тега возможно, но только в некоторых случаях: не нужен JS или не нужен IE. Увы, это не ко мне. Копаем дальше.

Комбинация вложенных тегов object или object&embed
На мой взгляд, вложенные теги - бестолковая комбинация [13], права на жизнь не имеет. Лишняя возня с определением реально используемого тега ID для JS не добавляет привлекательности. object&embed - это вообще не пойми что по причине вышеописанных проблем у embed. Изначально, наверное, идея была в том, чтобы обойти браузеры не поддерживающие тег object, но такие экземпляры вымерли ещё 10 лет назад даже на мобильных устройствах.     
А вот пара тегов object и условных комментариев явно имеет право на жизнь, хотя и усложняет код.

object
Тег рекомендован W3C, так что в теории всё должно быть хорошо. Но на практике имеется миллион глюков и куча устаревшей и мусорной информации вокруг его использования. Честно говоря, умаялся я этот мусор разгребать, всё описывать не буду, только основные находки и соображения:
  1. Указывать атрибут classid для IE нет необходимости. Отлично работает и просто type="application/x-shockwave-flash";
  2. Наличие атрибута data убивает streaming в IE [1]! Кроме того, IE ещё и уродливую рамку на месте объекта отображает, пока всё не загрузит [6];
  3. Отсутствие атрибута data приводит к незагрузке ролика в Firefox! А вот всем остальным браузерам достаточно параметра movie;
  4. Атрибут STANDBY, позволяющий разместить комментарий типа "Идет загрузка" пока грузится swf не работает в IE. В остальных не проверял, т.к. во всех остальных всегда работает streaming;
  5. Атрибут codebase="http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,124,0" отлично работает в IE, но не работает в остальных браузерах. А IE предлагает загрузить новую версию плеера, если текущая устарела. Наверное лучше, по возможности, использовать "#version=9,0,0,0" т.к. майкрософт распространяет версию 9,0,115,0 в составе SP3. Этим мы несколько уменьшим кол-во загрузок, т.е. будем меньше беспокоить наших пользователей;
  6. Атрибут codetype можно не использовать, т.к. type достаточно;
  7. Эксперименты с атрибутами тега param valuetype и type не увенчались успехом;
  8. Эксперименты с data="data:application/x-shockwave-flash," не увенчались успехом.
Возможные решения
Видно, что всё вертится вокруг борьбы с атрибутом data:
  1. Можно не бороться, а одновременно использовать и атрибут data, и параметр movie.
    <object width="400" height="300" type="application/x-shockwave-flash"
    data="http://example.org/flash.swf">
      <param name="movie" value="http://example.org/flash.swf">
    </object>
    Работать будет везде, но в IE работать будет уродливо.
  2. Можно бороться только с Firefox присвоением data через JS
    <object id="swf1" width="400" height="300" type="application/x-shockwave-flash">

      <param name="movie" value="http://example.org/flash.swf">
    </object>
    <js> document.getElementById("swf1").data = "http://example.org/flash.swf" </js>
    Причем на firefox можно и не проверять - отлично работает и без этого.
    Способ в целом неплохой, но требует включенного JS под Firefox.
  3. Можно бороться только с IE через условные комментарии
    <!--[if IE]>
      <object id="swf1" width="400" height="300" type="application/x-shockwave-flash">
    <![endif]-->
    <!--[if !IE]><-->
      <object id="swf1" width="400" height="300" type="application/x-shockwave-flash" data="http://example.org/flash.swf">
    <!--><![endif]-->

      <param name="movie" value="http://example.org/flash.swf">

    </object>
    Это, пожалуй самое лучшее решение. Работает везде (похоже, что вообще в абсолютно всех браузерах) и работает красиво, плавно, без посторонних эффектов.
Понятное дело, что я за последний вариант. Замечания по нему:
  1. Небольшое дублирование кода. Настолько небольшое, что это и недостатком сложно назвать;
  2. Забыли про щелчки для активации;
  3. Забыли про альтернативный контент, и про инсталляцию плеера, если его нет;
  4. Забыли про обновление плеера, если устарел.
Обновление и инсталляция плеера
Это тема сложная, достойная рассмотрения в следующей (ещё не написанной) части статьи, поэтому сейчас ограничусь общими соображениями:
  1. Вообще-то плеер умеет обновляться и сам. Он проверяет наличие обновлений при загрузке очередного ролика, но не чаще чем раз в 30 дней. Можно и помочь браузеру обновит плеер, задав атрибут codebase="http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0". Это имеет смысл только для IE, т.к. codebase должен указывать только на свой домен, что в данном случае не соблюдается. IE на это плюет, а остальные блюдут. Причем, можно не повторять codebase у каждого тега object, а ограничиться однократным упоминанием.
  2. Если плеера нет, или он недоступен, то будет отображен так называемый альтернативный контент. Соответственно, нужно этим контентом сказать пользователю, что ему нужно установить плеер.
    <a href="http://www.adobe.com/go/getflashplayer">
    Для корректной работы сайта вам необходимо установить проигрыватель Adobe Flash<br />
    <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Установить" /></a>
    А если используется IE, то теоретически можно и ничего не говорить, т.к. вначале отработает предложение установить плагин по codebase, а после этого пользователь должен пенять на себя.
    Кстати, заметили, что все ссылки уже давно переехали с macromedia.com на adobe.com?
Щелчок для активации
Это, пожалуй, самая большая проблема, также достойная рассмотрения в следующей (ещё не написанной) части статьи. На данный момент щелчка требуют IE6 и IE7 без последних обновлений и Opera9. Т.е. проблема вроде как изживает сама себя, но всё-таки хотелось бы решить красиво. Жаль, что программно узнать необходимость фикса невозможно.

Заключение
Вот ссылки на пример:
  • HTML (Content-Type: text/html);
  • XHTML (Content-Type: application/xhtml+xml) - напоминаю, xhtml в IE не работает.
Предложено достаточно элементарное, но весьма даже рабочее решение. Работа над недоработками ведется. Исследована применимость тега embed, который также небезынтересен.

Я специально оговорюсь: я знаю, что я не открыл Америку. Как минимум один человек из Чехии уже публиковал аналогичное решение, но проблема в том, что очень часто чтобы задать вопрос нужно знать ответ. Этой заметкой я описываю не только найденное решение, но и кучу сопутствующей информации. Надеюсь, кому-нибудь это поможет. Кроме того, работа не окончена, я ещё буду возвращаться к этой теме. Я был бы очень благодарен за любые отзывы, критику и сообщения об ошибках.

4 коммент.:

Gleb Arestov комментирует...

очень круто! я искал чтонибудь без скриптов и что бы можно было полноценный контент вкладывать..
я так понимаю туда можно что угодно втравить со своими стилями и семантикой.?

Павел комментирует...

Не совсем понял, что тебе нужно "втравить". По идее - все достаточно просто, чтобы на этой основе сделать что угодно.

Gleb Arestov комментирует...

http://www.w3.org/QA/2008/09/howto-insert-youtube-video.html

Павел комментирует...

У него стриминг, похоже, не работает. Я так и не дождался проигрsвания видео. IE8B2.