'transform3d' no funciona con position: niños fijos

140

Tengo una situación en la que, en circunstancias normales de CSS, un div fijo se colocaría exactamente donde se especifica ( top:0px, left:0px).

Esto no parece respetarse si tengo un padre que tiene una transformación translate3d. ¿No estoy viendo algo? He probado otras opciones de estilo de transformación de kit de web y opciones de origen de transformación, pero no tuve suerte.

He adjuntado un JSFiddle con un ejemplo donde hubiera esperado que el cuadro amarillo estuviera en la esquina superior de la página en lugar de dentro del elemento contenedor.

Puede encontrar a continuación una versión simplificada del violín:

#outer {
    position:relative; 
    -webkit-transform:translate3d(0px, 20px , 0px); 
    height: 300px; 
    border: 1px solid #5511FF; 
    padding: 10px;
    background: rgba(100,180,250, .8); 
    width: 80%;
}
#middle{
    position:relative; 
    border: 1px dotted #445511; 
    height: 300px; 
    padding: 5px;
    background: rgba(250,10,255, .6);
}
#inner {
    position: fixed; 
    top: 0px;
    box-shadow: 3px 3px 3px #333; 
    height: 20px; 
    left: 0px;
    background: rgba(200,180,80, .8); 
    margin: 5px; 
    padding: 5px;
}
<div id="container">
    Blue: Outer, <br>
    Purple: Middle<br>
    Yellow: Inner<br>
    <div id="outer"> 
        <div id="middle">
            <div id="inner">
                Inner block
            </div>
        </div>
    </div>
</div>

¿Cómo puedo hacer que translate3d funcione con niños de posición fija?

Juan carlos moreno
fuente
El mismo problema ocurre con el filtro también: stackoverflow.com/q/52937708/8620333
Temani Afif el

Respuestas:

196

Esto se debe a que transformcrea un nuevo sistema de coordenadas local, según las especificaciones del W3C :

En el espacio de nombres HTML, cualquier valor que no sea nonepara la transformación da como resultado la creación de un contexto de apilamiento y un bloque contenedor. El objeto actúa como un bloque contenedor para descendientes posicionados fijos.

Esto significa que el posicionamiento fijo se vuelve fijo al elemento transformado, en lugar de la ventana gráfica.

Actualmente no hay una solución alternativa que yo sepa.

También está documentado en el artículo de Eric Meyer: Elementos fijos sin reparar con transformaciones CSS .

saml
fuente
Gracias, no me había dado cuenta de que la especificación real tenía esa información ... Creo que obtuve el equivalente a la respuesta matemática: "por definición" :)
Juan Carlos Moreno
3
@INT, no creo que haya una solución para esto. Hay un caso de uso importante para no permitir soluciones alternativas: la entrada proporcionada por el usuario podría cubrir controles fuera de su área designada (piense en un correo electrónico malicioso que agrega opciones a la barra de herramientas de gmail). La mejor solución sería evitar las transformaciones por el momento si va a usar fijo desde adentro.
saml
1
¿No establecer el atributo superior CSS en cualquier ventana.scrollHeight es trabajo? Es posible que tenga que posicionarlo absolutamente también, pero algo como esto debería ser factible, ¿no? (Demasiado perezoso para probar en este momento)
Brad Orego
@bradorego tenías razón, acabo de agregar el código que usé.
UzumakiDev
Esto todavía está cambiando en la especificación por lo que puedo decir. Consulte el error 16328: el uso del "bloque que contiene" no coincide con la definición CSS2.1 .
Thirdender
13

Tuve un parpadeo en mi navegador superior fijo cuando los elementos de la página usaban transformación, lo siguiente aplicado a mi navegador superior resolvió el problema de salto / parpadeo:

#fixedTopNav {
    position: fixed;
    top: 0;
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
}

Gracias a esta respuesta en SO

rob.m
fuente
12

Como sugirió Bradoergo, solo obtenga la ventana scrollTopy agréguela a la posición absoluta superior como:

function fix_scroll() {
  var s = $(window).scrollTop();
  var fixedTitle = $('#fixedContainer');
  fixedTitle.css('position','absolute');
  fixedTitle.css('top',s + 'px');
}fix_scroll();

$(window).on('scroll',fix_scroll);

Esto funcionó para mí de todos modos.

UzumakiDev
fuente
3
¡Funciona! pero en lugar de vincularme a "ventana", tuve que vincularme al div que se estaba desplazando. Además, el elemento fijo parpadea.
entrenar el
¿Qué tiene que hacer jQuery aquí?
FlorianB
Esto podría haberlo hecho, pero como mencionó @train, parpadea.
Etienne Dupuis
Sí, esto no se actualiza lo suficientemente rápido como para ser lo suficientemente limpio para mi uso: - / buena idea aunque
reid
Esta es una práctica muy mala, no hagas cambios de estilo con js
Wannes
4

En Firefox y Safari puede usar en position: sticky;lugar de, position: fixed;pero no funcionará en otros navegadores. Para eso necesitas JavaScript.

Dušan
fuente
2
El posicionamiento fijo es un híbrido de posicionamiento relativo y fijo, y es realmente experimental , recomiendo encarecidamente evitar esto, ya que aún no es estándar.
Farside
1
AFAIK en Firefox y Safari simplemente puede usar position:fixedy funcionaría como se esperaba de todos modos.
oriadam
@oriadam no, tengo el problema cuando el padre usa translate3d y la posición fija de los niños está volando en algunos casos. Intentará usarlo stickymientras 'ya es compatible con los principales navegadores: caniuse.com/#feat=css-sticky
Lukas Liesis
stickypuede ser una solución, funciona en el navegador moderno.
aboutqx
3

En mi opinión, el mejor método para lidiar con esto es aplicar la misma traducción, pero separar a los niños que necesitan ser reparados de su elemento padre (traducido); y luego aplica la traducción a un div dentro del position: fixedcontenedor.

Los resultados se parecen a esto (en su caso):

<div style='position:relative; border: 1px solid #5511FF; 
            -webkit-transform:translate3d(0px, 20px , 0px); 
            height: 100px; width: 200px;'> 

</div>
<div style='position: fixed; top: 0px; 
            box-shadow: 3px 3px 3px #333; 
            height: 20px; left: 0px;'>
    <div style='-webkit-transform:translate3d(0px, 20px, 0px);'>
        Inner block
    </div>
</div>

JSFiddle: https://jsfiddle.net/hju4nws1/

Si bien esto puede no ser ideal para algunos casos de uso, por lo general, si está arreglando un div, probablemente no le importe qué elemento es su padre / dónde cae en el árbol de herencia en su DOM y parece resolver la mayor parte del dolor de cabeza - mientras permite ambos translatey position: fixedvivir en armonía (relativa).

reid
fuente
0

Me encontré con el mismo problema. La única diferencia es que mi elemento con 'position: fixed' tenía sus propiedades de estilo 'top' e 'left' establecidas desde JS. Entonces pude aplicar una solución:

var oRect = oElement.getBoundingClientRect();

El objeto oRect contendrá coordenadas superiores e izquierdas reales (relativas al puerto de visualización). Para que pueda ajustar sus propiedades reales oElement.style.top y oElement.style.left.

Mike Dobrin
fuente
Esto funciona en IE y Chrome, pero no en el navegador estándar de Android. La izquierda es un número pero siempre se dibuja en la posición 0
Adaptabi
0

Tengo una barra lateral fuera del lienzo que usa -webkit-transform: translate3d. Esto me impedía colocar un pie de página fijo en la página. Resolví el problema apuntando a una clase en la página html que se agrega a la etiqueta en la inicialización de la barra lateral y luego escribiendo un css: not qualifier para indicar "-webkit-transform: none;" a la etiqueta html cuando esa clase no está presente en la etiqueta html. ¡Espero que esto ayude a alguien con este mismo problema!

WeisbergWeb
fuente
0

Intente aplicar la transformación opuesta al elemento hijo:

<div style='position:relative; border: 1px solid #5511FF; 
            -webkit-transform:translate3d(0px, 20px , 0px); 
            height: 100px; width: 200px;'> 
    <div style='position: fixed; top: 0px; 
                -webkit-transform:translate3d(-100%, 0px , 0px); 
                box-shadow: 3px 3px 3px #333; 
                height: 20px; left: 0px;'>
        Inner block
    </div>
</div>
Mari Do
fuente
0

Agregue una clase dinámica mientras el elemento se transforma. $('#elementId').addClass('transformed'). Luego continúa declarando en css,

.translat3d(@x, @y, @z) { 
     -webkit-transform: translate3d(@X, @y, @z); 
             transform: translate3d(@x, @y, @z);
      //All other subsidaries as -moz-transform, -o-transform and -ms-transform 
}

luego

#elementId { 
      -webkit-transform: none; 
              transform: none;
}

luego

.transformed {
    #elementId { 
        .translate3d(0px, 20px, 0px);
    }
}

Ahora, position: fixedcuando se proporciona un valor de propiedad topy z-indexen un elemento secundario, funciona bien y permanece fijo hasta que el elemento primario se transforma. Cuando se revierte la transformación, el elemento hijo aparece nuevamente como fijo. Esto debería facilitar la situación si en realidad está utilizando una barra lateral de navegación que se abre y cierra con un clic, y tiene un conjunto de pestañas que debe permanecer fijo mientras se desplaza hacia abajo en la página.

mr.G
fuente
-1

Una forma de lidiar con esto es aplicar la misma transformación al elemento fijo:

<br>
<div style='position:relative; border: 1px solid #5511FF; 
            -webkit-transform:translate3d(0px, 20px , 0px); 
            height: 100px; width: 200px;'> 
    <div style='position: fixed; top: 0px; 
                -webkit-transform:translate3d(0px, 20px , 0px); 
                box-shadow: 3px 3px 3px #333; 
                height: 20px; left: 0px;'>
        Inner block
    </div>
</div>
fgassert
fuente
1
En IE, el error no existe en primer lugar
oriadam