2012-07-02 17 views
14

He estado experimentando un problema en las versiones móviles de webkit (específicamente Webkit 534.46 en iOS 5.1.1 como Safari móvil y ahora Chrome para iOS) que no ocurre en ningún navegador de escritorio que yo ' Has visto. (es decir, los demos continuación deben considerarse en una versión móvil de webkit.)Problema de reflujo de Mobile Webkit

Here is a live example of the issue. El núcleo de la CSS es extremadamente sencillo. Se posiciona un índice alfabeto a lo largo de la izquierda de la página:

#index { 
    left:0; margin:0; padding:0; position:fixed; top:0; width:3em; 
} 

El problema ocurre cuando un elemento es de posición fija sobre la parte superior del cuerpo. Se puede interactuar completamente hasta que el desplazamiento cambie y luego deje de aceptar la entrada. Si yo (manualmente) sacude el desplazamiento incluso un píxel, se vuelve a activar. El ejemplo se mantuvo lo más simple posible y no utiliza ningún JavaScript. Después de aporrearlo realmente, descubrí que parece que el elemento cree que está desplazado pero que ha sido reparado visualmente. En otras palabras, si hace clic en 'A', intente hacer clic nuevamente en 'A', a veces obtendrá un segundo clic, pero estará más abajo en la lista. Esto me pareció un problema de reflujo de CSS. Sé que el webkit móvil intenta reducir el número de reflows.

Here is a live example of the workaround.

Puedo usar JS para forzar el CSS de todo el documento vuelva a fluir el desplazamiento (con un acelerador que evita que suceda hasta 100 ms después del desplazamiento) que parece solucionar este problema en el sencillo ejemplo. Desafortunadamente, esto no ayuda a la versión de este problema en el mundo real.

This is the code for the issue page and the workaround script.

Mi pregunta es lo que está sucediendo aquí y hay una solución CSS que me falta? Específicamente, tengo curiosidad por saber si algún gurú de CSS puede averiguar cuál es la situación del diseño que impide que los clics lleguen al lugar correcto en el elemento fijo. Una mejor comprensión podría ayudar a encontrar una solución real.

Edit: Olvidé mencionar que el ejemplo obliga explícitamente a la ventana gráfica al tamaño de la ventana. Por lo tanto, el usuario no puede acercar/alejar, lo que significa que la posición: fija debe anclar el elemento en el lado izquierdo de la ventana.

Actualización (20/09/2012): Esto parece estar fijo en Safari Mobile en iOS 6 (así como UIWebView). Cualquier solución debe primero comprobar para asegurarse de que está en IOS < 6. Por ejemplo, el uso de CssUserAgent este sería el resultado:

if (parseFloat(cssua.ua.ios) < 6) { /* ... */ } 
+0

Todavía estoy repasando las diversas soluciones en las dos respuestas para encontrar el "mejor". Les di a ambos un +1 para los enlaces. Otorgaré la recompensa a lo que arregle mi problema. ¡Gracias! – mckamey

+0

Todavía estoy buscando una solución que funcione en mi caso particular, pero la ventana de recompensas se está acabando, así que se lo adjudicaré a @Paul Sweatte ya que él respondió primero y sus enlaces tienen más variaciones de solución. ¡Gracias a todos! – mckamey

Respuesta

9

La respuesta que realmente resuelve mi problema particular era una variación de una solución encontró in one of @Paul Sweatte's links:

En esencia, un div llanura que es más alto que se añade al cuerpo. Cuando se elimina, hace que el cuerpo se desplace o refluya de manera efectiva. Establecer el retraso en 0 ms entre la adición/eliminación es suficiente para permitir que el DOM vuelva a calcular sin causar ningún parpadeo. Esta fue la secuencia de comandos mínima que pude encontrar que resolvió completamente el problema de todos los elementos position:fixed en mi instancia particular de este problema.

var hack = document.createElement("div"); 
hack.style.height = "101%"; 
document.body.appendChild(hack); 
setTimeout(function(){ 
    document.body.removeChild(hack); 
    hack = null; 
}, 0); 
2

Parece que este es un known bug:

el problema central es: si la página se mueve programáticamente (es decir, el usuario no causó el desplazamiento) los elementos dentro del elemento de arreglo no están disponibles.

Uso posicionamiento absoluto, change the markup, o usar uno de los híbridos workarounds.

+0

Tenga en cuenta que el ejemplo que publiqué específicamente no usa JavaScript para desplazarse. Entonces, esto es puramente un problema de CSS. – mckamey

+0

Gracias. He actualizado mi respuesta con nueva información. –

2

Mi instalación de iWebInspector está muy estropeada ahora, pero después de jugar con jsfiddle y el sim de iOS parece que su corazonada es correcta -a pesar de su posición: fija, el navegador cree que la página se ha desplazado y arruina el hacer clic en los objetivos.

Se parece mucho a esto es el mismo problema que iOS Safari: Anchors within a fixed positioned element only work once, que tampoco se ha resuelto con CSS puro. También relacionado: Fixed position navbar only clickable once in Mobile Safari on iOS5.

Tangencialmente, y estoy seguro de que ya se ha notado, no es posible desplazarse por el lado izquierdo, por lo que en un iPhone el índice solo muestra A-M.

+1

Gracias. Sí, no me molesté en hacer el diseño receptivo del lado izquierdo, traté de eliminar todo lo que no estaba relacionado con el error. – mckamey

+0

Sí, tiene sentido. Me alegro de que hayas encontrado una solución viable. – egid

6

Irónicamente, mi solución de reflujo original (vinculada a en la pregunta) ahora también está funcionando en mi aplicación real. Poner una variante aquí en el caso es útil para cualquier otra persona. Se puede invocar en cualquier elemento contenedor, o si no se pasa nada, se vuelve a refluir todo el documento.

var forceReflow = function(elem){ 
    elem = elem || document.documentElement; 

    // force a reflow by increasing size 1px 
    var width = elem.style.width, 
     px = elem.offsetWidth+1; 

    elem.style.width = px+'px'; 

    setTimeout(function(){ 
     // undo resize, unfortunately forces another reflow 
     elem.style.width = width; 
     elem = null; 
    }, 0); 
}; 

Lo bueno de esto es que no requiere crear/agregar/quitar elementos, solo ajustar el contenedor.

+0

¿Sabes cómo evitar que se muestre contenido roto antes del reflujo? Es visible por un tiempo muy corto ~ 50ms, pero es notorio para los usuarios. –

+0

¿Ves el contenido roto incluso cuando 'setTimeout' utiliza un valor de' 0'? Si es así, es posible que deba realizar optimizaciones generales que mejoren la velocidad de representación de la página. [Pruebe algunas de las sugerencias aquí.] (Https://developers.google.com/speed/pagespeed/) Por lo general, lo que he visto es que las personas usan el evento jQuery ready para crear su UI, que es muy lenta. – mckamey

+0

IIRC, agregar una clase ficticia a un elemento (por ejemplo, ''foo' + Date.now()') debería provocar un reflujo, y no es necesario que elimines la clase (a menos que te importe la limpieza). – hayavuk

0

Creo que esto es mejor y logra el mismo efecto, permitiendo que los enlaces se puedan hacer clic en pies de página fijos. De alguna manera, al ocultar urlbar los enlaces en el pie de página fijo no se pueden hacer clic hasta que se desplaza un poco. También he visto esto al enfocar las entradas, y adjunto un controlador de eventos a todos los eventos de enfoque para disparar esto también. Hago esto con dojo para adjuntar los eventos.

 if(navigator.userAgent.match(/iPhone/i)){ 
     /* The famous iOS can't-click-links until touch fix, I attach onfocus */ 
      query('input,textarea,select', this.domNode).on('focus', function(el){ 
       document.documentElement.style.paddingRight = '1px'; 
       setTimeout(function() { 
       document.documentElement.style.paddingRight = ''; 
       }, 0); 
      }); 
     } 
+1

Mejor que qué? Es la misma solución que [mi original] (http: // stackoverflow.com/a/11479118/43217) pero con valores codificados. Lo que debe suceder es forzar el reflujo. – mckamey

0

Aquí hay una variación de la solución de McKamey. Evita el reflujo dos veces, y puede ayudar con el parpadeo (según su aplicación):

setTimeout(function(){ 
    document.body.style.borderBottom = 
     document.body.style.borderBottom === 'none' ? '1px solid white' : 'none'; 
}, 0); 
+0

¿No necesita quitar la línea blanca (especialmente en un fondo que no sea blanco)? Ese sería su segundo reflujo. – mckamey

+0

Puede establecer el color como transparente sobre un fondo que no sea blanco para evitar un segundo reflujo. – csytan

Cuestiones relacionadas