Wednesday, April 8, 2009

position:absolute html element coordinates, offsetTop, offsetLeft, IE6

Речь пойдёт об очень больном месте для любого веб-разработчика - IE6.

Проблема встала достаточно просто. Есть input, под ним разметка. Нужно отобразить div сразу ниже input'а (на псевдоязыке: input.boottom=div.top), но чтобы этот div был поверх остальной разметки (т.е. увеличен z-index). Так вот, для этого мне нужно абсолютно спозиционировать div, а для этого нужно вычислить абсолютные координаты input'а.

Для вычисления абсолютных координат элемента в Интернете везде предлагается в цикле бежать по его offsetParent'ам до body и суммировать offsetTop (offsetLeft). Но в IE6 столь попсовое решение не работает, когда какой-то из parent'ов обладает бордюром. То есть размер бордюра не учитывается. Вот типичный пример этого решения из Интернета:
     function getObjCoordsIE6Usual(element) {
var res = new Object();
res.x = 0; res.y = 0;
if (element !== null) {
res.x = element.offsetLeft;
res.y = element.offsetTop;
var offsetParent = element.offsetParent;
while (offsetParent !== null) {
res.x += offsetParent.offsetLeft;
res.y += offsetParent.offsetTop;

if (offsetParent != document.body && offsetParent != document.documentElement) {
res.x -= offsetParent.scrollLeft;
res.y -= offsetParent.scrollTop;
}
offsetParent = offsetParent.offsetParent;
}
}
return res;
}

Естественно, это fial. Ниже приведу пример страницы, на которой можно протестить этот fial.

Слегка взгуглив, я нашёл, что "clientLeft Retrieves the distance between the offsetLeft property and the true left side of the client area. " (http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx)

Таким образом, суммируя ещё и clientLeft, получаем вроде бы реальные координаты для IE6.
     function getObjCoordsIE6Right(element) {
var res = new Object();
res.x = 0; res.y = 0;
if (element !== null) {
res.x = element.offsetLeft;
res.y = element.offsetTop;
var offsetParent = element.offsetParent;
while (offsetParent !== null) {
res.x += offsetParent.offsetLeft + offsetParent.clientLeft;
res.y += offsetParent.offsetTop + offsetParent.clientTop;

if (offsetParent != document.body && offsetParent != document.documentElement) {
res.x -= offsetParent.scrollLeft;
res.y -= offsetParent.scrollTop;
}
offsetParent = offsetParent.offsetParent;
}
}
return res;
}
Пример страницы, на которой это можно проверить.



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML Transitional//EN">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<html>
<head>
<title></title>

<script language="javascript">
function ShowInputCoords() {
var inp = document.getElementById('input');
var res = getObjCoordsIE6Usual(inp);
alert(res.x + ' ' + res.y);
res = getObjCoordsIE6Right(inp);
alert(res.x + ' ' + res.y);
}

function getObjCoordsIE6Usual(element) {
var res = new Object();
res.x = 0; res.y = 0;
if (element !== null) {
res.x = element.offsetLeft;
res.y = element.offsetTop;
var offsetParent = element.offsetParent;
while (offsetParent !== null) {
res.x += offsetParent.offsetLeft;
res.y += offsetParent.offsetTop;

if (offsetParent != document.body && offsetParent != document.documentElement) {
res.x -= offsetParent.scrollLeft;
res.y -= offsetParent.scrollTop;
}
offsetParent = offsetParent.offsetParent;
}
}
return res;
}

function getObjCoordsIE6Right(element) {
var res = new Object();
res.x = 0; res.y = 0;
if (element !== null) {
res.x = element.offsetLeft;
res.y = element.offsetTop;
var offsetParent = element.offsetParent;
while (offsetParent !== null) {
res.x += offsetParent.offsetLeft + offsetParent.clientLeft;
res.y += offsetParent.offsetTop + offsetParent.clientTop;

if (offsetParent != document.body && offsetParent != document.documentElement) {
res.x -= offsetParent.scrollLeft;
res.y -= offsetParent.scrollTop;
}
offsetParent = offsetParent.offsetParent;
}
}
return res;
}

</script>

</head>
<body>
<input id="Button1" type="button" value="click" onclick="ShowInputCoords()" />
<table>
<tbody>
<tr>
<td style="border: solid 6px;">
<input id="input" name="input" value="" />
</td>
</tr>
</tbody>
</table>
</body>
</html>
UPD. У jQuery на эту тему тоже нифиговые костыли, но они не сработали у меня... (см. последний метод по ссылке) : http://www.koders.com/javascript/fid69E7017C9DC7FDEFF58D3B1C36F15B1D22EBA424.aspx?s=%22Yehuda+Katz%22

No comments:

Post a Comment