Кроссбраузерный DHTML

Начинающие веб-программисты рано или поздно сталкиваются с тем, что их скрипт, любовно написанный (или позаимствованный) и прекрасно работающий на домашнем компьютере с MSIE 5.5, почему-то не работает у соседа или клиента на его Opera, Mozilla или Netscape.

Цель настоящей статьи - рассмотреть имеющиеся различия в DHTML-объектах и функциях у нынешних браузеров. Предполагается, что читатель уже более-менее знаком с программированием по крайней мере под один из браузеров.

Оглавление

  • Определение браузера
  • Окна и документы
  • Формы
    • Доступ к формам
    • Формы и Mozilla
    • и Netscape и Opera
  • Картинки
  • Слои
    • Доступ к слою
    • Доступ к CSS-свойствам слоя
    • Различия в CSS-свойствах
      • Кроссбраузерная прокрутка
    • Не CSS-свойства
    • Изменение содержимого слоя
    • Динамическое создание слоев через do*****ent.write в Netscape 4
  • Мышь
      События мыши (пока не готово)-->
    • Отслеживание координат мыши

Определение браузера

Браузеров и их версий довольно много, но многие из них не различаются между собой пониманием DHTML. Поэтому есть смысл разбить их на несколько групп, названных по наиболее распространенному представителю. Проверять на принадлежность к той или иной группе будем через поддержку испытуемым браузером тех или иных объектов:

isDOM=do*****ent.getElementById //DOM1 browser (MSIE 5+, Netscape 6, Opera 5+)
isMSIE=do*****ent.all && do*****ent.all.item //Microsoft Internet Explorer 4+
isNetscape4=do*****ent.layers //Netscape 4.*
isOpera=window.opera //Opera
isOpera5=isOpera && isDOM //Opera 5+
isMSIE5=isDOM && isMSIE //MSIE 5+
isMozilla=isNetscape6=isDOM && !isMSIE && !isOpera //Mozilla или Netscape 6.*

Последняя строчка спорна, т. к. не обязательно все, что не Опера и не MSIE - Mozilla. Однако если появятся браузеры, которые не совместимы ни с MSIE, ни с Opera, то с чем же им еще быть совместимыми, как не с Mozilla (Netscape 6)? Больше не с кем. Для особо ответственных случаев, когда надо наверняка отбросить все неизвестные браузеры, можно воспользоваться тем, что все современные Mozillы содержат в navigator.appName строчку "Netscape", т.е.

isMozilla=isNetscape6=isDOM && (navigator.appName=="Netscape")

Окна и документы

В разных браузерах по-разному вызываются такие свойства, как размеры окна, размеры документа, показатели прокрутки и т.д.

Размеры рабочей области окна

  • MSIE 4+ - do*****ent.body.clientWidth, clientHeight
  • Netscape, Mozilla, Opera - innerWidth, innerHeight
Координаты верхнего левого угла окна
  • MSIE 4+ - screenLeft, screenTop
  • Netscape, Mozilla, Opera - screenX, screenY>
Размеры содержимого документа
  • MSIE 4+ - do*****ent.body.scrollWidth, scrollHeight
  • Netscape, Mozilla - do*****ent.width, height
  • Opera - do*****ent.body.style.pixelWidth, pixelHeight
Прокрутка (scrolling)
  • MSIE 4+ - do*****ent.body.scrollLeft, scrollTop
  • Netscape, Mozilla, Opera - pageXOffset, pageYOffset

В MSIE в документе должен присутствовать тег , иначе do*****ent.body не будет определено.

ФормыДоступ к формам

В MSIE такой код прекрасно работает:


......
myform.mytext.value="hello"

Но в 4-ом Netscape этот код выдает ошибку. Там нельзя так обращаться к формам. Необходимо писать do*****ent.myform.mytext.value="hello" - это будет работать и там, и там. Чтобы избежать возможных конфликтов имени формы с другими объектами do*****ent лучше писать do*****ent.forms.myform.mytext.value или do*****ent.forms["myform"].elements["mytext"].value. Последняя запись рекомендуется в случаях, когда имя формы или ее элемента могут содержать недопустимые для имени переменной в JavaScript символы.

Формы и Mozilla

В Mozilla лучше не обращаться к элементам страницы (особенно формам) до наступления события onload.

и NetscapeВ Netscape у объекта select нет свойства value. Для выбора нужного option пользуйтесь проверкой select.options[n].value и установкой соответствующего select.selectedIndex. Пользоваться select.options[n].selected=true/false не рекомендуется из-за проблем с Opera (см. далее). и Opera

В Opera старых версий (напр. 5.10, в отличие от, к примеру, 5.12) нельзя выбрать опцию select через select.options[n].selected=true. Вместо этого нужно писать select.selectedIndex=n.

Картинки

Доступ с картинкам, т. е. объектам, создаваемым тегом , осуществляется через коллекцию do*****ent.images[]. Но у Netscape 4 есть особенность в вызове картинки, если она вставлена в слой (см. ниже).

Слои

Если в MSIE 4+ и Mozilla (он же Netscape 6) слоем может быть любой элемент страницы, то в Netscape 4 и Opera 5 это обычно контейнер

с определенным стилями absolute или relative расположением. Некоторые рекомендуют использовать в Netscape 4 тег , т. к. он лучше понимается Нетскейпом. Поэтому те случаи, когда

и в 4-ом Netscape ведут себя по-разному, возможно, я рассмотрю в одной из будущих статей. Но эти случаи достаточно редки и специфичны и связаны с глюками в форматировании содержимого слоев.

В Netscape 4 не используйте в именах классов (class=) и идентификаторов (id=) символ подчеркивания "_", в противном случае Netscape не увидит этого элемента.

Доступ к слою

Доступ к слоям по-разному осуществляется в разных браузерах. А именно:

  • MSIE 4+ - do*****ent.all[layerName]
  • Netscape 4 - do*****ent.layers[layerName]
  • DOM1 (MSIE 5+, Mozilla, Opera 5) - do*****ent.getElementById(layerName)

Можно порекомендовать такую функцию:

function layer(layerName){
//DOM1
if(do*****ent.getElementById) return do*****ent.getElementById(layerName)
//MSIE4
if(do*****ent.all) return do*****ent.all[layerName]
//Netscape 4
if(do*****ent.layers) return do*****ent.layers[layerName]
//неподдерживаемый браузер
return null
}

С доступом к слоям в Netscape 4 имеется один аспект. От связан с вложенными (nested) слоями, т. е. со слоями, которые описаны внутри контейнеров другого слоя. Пример (предполагается, что в CSS для тегов

задано допустимое свойство position):

xxx

Если в MSIE 4+ можно вызвать слой "cool" через do*****ent.all["cool"], то в Netscape 4 do*****ent.layers["cool"] вернет undefined. Для вызова вложенного слоя придется написать такую конструкцию:

do*****ent.layers["mylayer"].do*****ent.layers["cool"]

То же самое касается и адресации других объектов, находящихся внутри слоя - картинок, форм, ссылок и т.д.

Стало быть, нашу функцию можно модернизировать таким образом:

//рекурсивный поиск по слоям
function findLayer(what, where){
if(!where) return
var i,l,parent
var len=where.length
for(i=0;iparent=where[i].do*****ent.layers
l=parent[what]
if(l) return l
l=findLayer(what, parent)
}
return false
}

function layer(layerName, parentLayerName){
if(do*****ent.getElementById) return do*****ent.getElementById(layerName)
if(do*****ent.all) return do*****ent.all[layerName]
if(do*****ent.layers){
if(parentLayerName){
return findLayer(layerName, eval(parentLayerName))
}else{
return findLayer(layerName, do*****ent.layers)
}
}
}

Теперь мы можем обратиться к нашему слою "cool" так: layer("cool","mylayer") или вообще layer("cool"), но последний вариант будет более "тормозным", т. к. компьютеру придется обходить всё дерево слоев до искомого. Похожее соображение приводит к тому, что логично единожды вызвать слой - var mylayer=layer("xxx"), а потом использовать переменную mylayer для дальнейшей работы со слоем.

С картинками, вставленными в слой, в Netscape 4 дело обстоит так же. Картинки в слое не входят в коллекцию do*****ent.images[] корневого документа, они принадлежат коллекции do*****ent.images[] этого слоя. Пример - у нас есть слой "layer", в нем есть картинка "image". Чтоб поменять у этой картинки src, пишем:

do*****ent.layers["layer"].do*****ent.images["image"].src="file.jpg"

Доступ к CSS-свойствам слоя

Доступ к CSS-свойствам слоя (расположение, видимость и т.д.) также по-разному осуществляется в разных браузерах. В MSIE 4 и DOM1-браузерах доступ к свойству осуществляется через объект .style. Пример (используется уже определенная нами функция вызова слоя):

// спрятать слой в MSIE4 и DOM1-браузерах
layer("mylayer").style.visibility="hidden"

В Netscape 4 у слоя нет поля style, доступ к свойствам осуществляется непосредственно:

// спрятать слой в Netscape 4
layer("mylayer").visibility="hide"

Можно заметить, что даже значение, которое нужно присвоить свойству .visibility, разное у разных браузеров. Хотя более новые версии 4-ого Netscape поддерживают не только "show"/"hide", но и "visible"/"hidden", как и MSIE.

Для доступа к стилям можно порекомендовать такую функцию:

function layerStyle(layerObject){
if(layerObject.style) return layerObject.style //доступ через style
return layerObject //доступ без style
}

Вместе с которой наш пример сократится до layerStyle(layer("mylayer")).visibility=isNetscape4?"hide":"hidden"

Надо, правда, отметить, что приведенный мной пример выглядит несколько громоздким. Это связано с тем, что он, не обладая большой практической пользой, призван лишь проиллюстрировать работу со слоями в разных браузерах. Но вы можете познакомиться с более аккуратно написанной мною же объектно-ориентированной библиотекой DHTML-функций KLayers.

Различия в CSS-свойствах

Хочу повторить, что доступ к CSS-свойствам по-разному осуществляется в разных браузерах.

Видимость слоя (visibility)

  • MSIE, Opera, Mozilla - .visibility="visible"/"hidden" (видимый/спрятанный)
  • Netscape 4 - .visibility="show"/"hide"
Цвет фона слоя
  • MSIE, Mozilla, Opera 6 - .backgroundColor="ЦВЕТ" (напр. "red","#ffee15")
  • Netscape 4 - .bgColor="ЦВЕТ"
  • Opera 5 - .background="ЦВЕТ" (работает только в том случае, если изначально через CSS для слоя был указан какой-либо фоновый цвет)
Фоновое изображение у слоя
  • MSIE, Mozilla, Opera 6 - .backgroundImage="url(url картинки)"
  • Netscape 4 - .background.src="url картинки"
Обрезка слоя (clip)

Позволяет сделать только часть слоя видимой. Может применяться для эффектов "распахивания", "выползания" или "скроллинга".

  • MSIE, Mozilla - .clip="rect(top,right,bottom,left)"
  • Netscape 4 - .clip.top="top", .clip.right="right" и т.д. (top, right, bottom, left - размеры в пикселах, т.е., к примеру, 120px)
  • Opera - не поддерживается

Для реализации прокручиваемого текста в новых браузерах (MSIE, Mozilla, Opera) удобно применять css-свойство overflow: hidden. Можно создать блок с overflow: hidden и фиксированными размерами, а внутрь его вложить другой блок, который и будем прокручивать. Для прокрутки достаточно менять ему .style.left и top (или .style.pixelLeft, pixelTop в Opera). В Netscape 4, само собой разумеется, для прокрутки слоя придется пользоваться свойством clip.

Не CSS-свойства

У слоев есть свойства, которые не определяются CSS. Это, к примеру, получившиеся габариты слоя, которые зависят от количества текста, помещенного в нем. Обращаться к этим свойствам надо минуя .style, т. е. просто layer.свойство.

Текущие координаты верхнего левого угла слоя на странице

  • MSIE, Opera, Mozilla - .offsetLeft, offsetTop (только для чтения)
  • Netscape 4 - .pageX, pageY (можно изменять, двигая слой абсолютно, т. е. относительно окна, а не родительских элементов, если такие есть)

Пример:

// Y-координата верха слоя
function getLayerTop(layer){
if(isMSIE || isOpera5 || isMozilla){
return layer.offsetTop
}else if(isNetscape4){
return layer.pageY
}
}

В DOM1-браузерах (MSIE, Opera, Mozilla) в случае вложенных слоев, т. е. когда слой вложен в другой слой, координаты .offsetLeft и .offsetTop отсчитываются относительно родительского слоя. Для получения ссылки на родительский элемент существует свойство .offsetParent. Можно пройтись по цепочке offsetParentов, суммируя их координаты, пока не дойдем до самого верхнего родителя - do*****ent.body.

Текущие размеры содержимого слоя

  • MSIE, Mozilla - .offsetWidth, offsetHeight
  • Netscape 4 - .do*****ent.width, height
  • Opera - .style.pixelWidth, pixelHeight
Изменение содержимого слояЗапись в слой
  • MSIE, Mozilla - .innerHTML=текст
  • Netscape 4 - .do*****ent.open()
    .do*****ent.write(текст)
    .do*****ent.close()
  • Opera - невозможно

В MSIE 4 не следует вызывать .innerHTML до наступления onload страницы.

В Netscape 4 есть глюк с записью русских букв в слой. Они превращаются либо в символы кодировки western, либо в знаки вопроса ("?????"). Решение этой проблемы может быть достигнуто через использование загрузки в слой другого документа (см. далее). В слой загружается документ с корректно выставленным charset, а потом в него печатается через do*****ent.write нужный текст.

Подгрузка другого документа в слой

В Netscape 4 слои имеют атрибут и свойство src, а также метод .load(url). Это позволяет записывать в слой содержимое любого документа.

В MSIE и Mozilla вместо этого есть тег


2008 © Computer repair