Aquí es una respuesta a mi propia pregunta que se me ocurrió hoy después de jugar con IE8, FF, Chrome y Safari.
Digamos que queremos plegar y desplegar un elemento div verticalmente (por lo que vamos a estar hablando sólo de la altura para simplificar) con un mínimo posible de JavaScript y jQuery no. Podría ser un cuadro de mensaje de error en línea que desea mostrar y ocultar muy bien en la página. El cuadro de mensaje en sí es elástico y no conoce sus dimensiones reales. Hay dos problemas generales que deben resolverse aquí:
Problema n. ° 1: las propiedades offsetHeight, clientHeight y scrollHeight son notoriamente inconsistentes en todos los navegadores. No puede confiar en ellos especialmente cuando margin/padding/border están configurados en algo distinto de 0 y cuando la altura de CSS es distinta a la predeterminada (es decir, cuando se dobla o se despliega realmente el elemento). Hay getComputedStyle(), pero está disponible solo en navegadores sanos y no en IE. OTOH, la propiedad Style actual de IE no devuelve los valores calculados como cabría esperar (por ejemplo, puede ver "auto" como valor de altura). Resulta que, sin margen/relleno/borde compensado, la altura es confiable y compatible en todos los navegadores modernos.
Problema # 2: la única manera (que yo sepa) para animar el elemento div es cambiar el estilo.altura, que, sin embargo, no incluye relleno y borde, y por lo tanto no puede animar la caja a 0 o comenzar su animación desde 0 para elementos con relleno y borde distintos de cero. (Además de eso, IE no acepta 0px como style.height, por lo que el tamaño mínimo sería 1px de todos modos).
La solución a ambos problemas es envolver su caja con otro div con estilo predeterminado, es decir, relleno/margen/borde todo configurado en 0, que es el estilo predeterminado para un nuevo div. La caja que desea doblar y desplegar debe estar dentro y no debe tener una configuración de margen, solo relleno y borde si lo desea. De esta forma, podrá (1) determinar de manera confiable la altura de su caja interna elástica a través de offsetHeight, y (2) animar la altura de la caja externa hacia y desde 1 píxel.
Por lo tanto, digamos que queremos animar esta:
<div id="errmsg" style="display:none">
<div class="errmsg">
<div class="window-close" onClick="javascript:showErrMsg('', this.parentNode.parentNode)"></div>
<div id="errmsg.text"></div>
</div>
</div>
El cuadro es invisible al principio. La clase "ventana cerrada" es una pequeña caja a la derecha con una cruz que se usa para ocultar el cuadro cuando se hace clic. Llamar a showErrMsg() con una cadena vacía dobla el cuadro de mensaje (ver a continuación).
código
Mi JavaScript para animar este cuadro de mensaje de error es como sigue (También estoy animando la opacidad que se omite aquí por simplicidad):
var ANIMATE_STEPS = 10;
var ANIMATE_DELAY = 20;
function _obj(obj, parent)
{
if (typeof obj == 'string')
obj = (parent ? parent : document).getElementById(obj);
return obj;
}
function _setStyleHeight(obj, h)
{
_obj(obj).style.height = Math.round(h) + 'px';
}
function _animateVertFold(obj, cur, by, lim)
{
obj = _obj(obj);
cur += by;
if (by < 0 && cur <= 1)
{
obj.style.display = 'none';
_setStyleHeight(obj, 1); // IE doesn't accept 0
}
else if (by > 0 && cur >= lim)
{
_setStyleHeight(obj, lim);
}
else
{
_setStyleHeight(obj, cur);
setTimeout('_animateVertFold(\'' + obj.id + '\', ' +
cur + ', ' + by + ', ' + lim + ')', ANIMATE_DELAY);
}
}
function _expandElem(obj)
{
obj = _obj(obj);
if (obj.style.display == 'none')
{
obj.style.overflow = 'hidden';
_setStyleHeight(obj, 1);
obj.style.display = 'block';
var innerDiv = obj.getElementsByTagName('div')[0]; // better way?
var h = innerDiv.offsetHeight;
if (h > 0)
_animateVertFold(obj, obj.offsetHeight, h/ANIMATE_STEPS, h);
}
}
function _shrinkElem(obj)
{
obj = _obj(obj);
if (!obj.style.display || obj.style.display != 'none')
{
obj.style.display = 'block';
obj.style.overflow = 'hidden';
var h = obj.offsetHeight;
_animateVertFold(obj, h, - h/ANIMATE_STEPS, h);
}
}
function showErrMsg(msg, id)
{
id || (id = '_errmsg');
obj = _obj(id);
if (msg != '')
{
_obj(id + '.text').innerHTML = msg;
_expandElem(obj);
}
else
_shrinkElem(obj);
}
Puede llamar showErrMsg() y el código se encargará del resto. Deberá definir la clase de cierre de ventana como algo que imita un botón de ventana de la GUI. Y, por supuesto, la clase "errmsg" como una caja con distinto color de fondo, borde y posiblemente cara de fuente también.
Siempre se puede mirar la fuente de jQuery (u otro kit de herramientas/biblioteca de su elección) para determinar el enfoque, y luego descartar (o reglamentar) las diferentes peculiaridades necesarias en diferentes entornos. –
pst, eso siempre es una opción, por supuesto, pero pensé que alguien con un conocimiento razonable de estos 4 navegadores, o alguien que ya lo haya hecho antes, le daría una respuesta de inmediato. Y comprender jQuery puede o no ser tan fácil. – mojuba
Creo que resolver el problema hight()/width() no va a llevar tanto tiempo como hacer que la animación se vea bien, lo que jquery hace por usted. – tster