'transform3d' non funziona con la posizione: figli fissi


140

Ho una situazione in cui, in normali circostanze CSS, un div fisso sarebbe posizionato esattamente dove è specificato ( top:0px, left:0px).

Questo non sembra essere rispettato se ho un genitore che ha una trasformazione translate3d. Non vedo qualcosa? Ho provato altre trasformazioni di webkit come lo stile e le opzioni di origine ma non ho avuto fortuna.

Ho allegato un JSFiddle con un esempio in cui mi sarei aspettato che la casella gialla fosse nell'angolo superiore della pagina anziché all'interno dell'elemento contenitore.

Di seguito puoi trovare una versione semplificata del violino:

#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>

Come posso fare in modo che translate3d funzioni con i bambini posizionati in modo fisso?


Lo stesso problema si verifica anche con il filtro: stackoverflow.com/q/52937708/8620333
Temani dopo il

Risposte:


196

Questo perché transformcrea un nuovo sistema di coordinate locali, come da specifica W3C :

Nello spazio dei nomi HTML, qualsiasi valore diverso da quello noneper la trasformazione comporta la creazione di un contesto di impilamento e di un blocco contenitore. L'oggetto funge da blocco contenitore per i discendenti posizionati fissi.

Ciò significa che il posizionamento fisso viene fissato all'elemento trasformato, anziché alla finestra.

Al momento non sono presenti soluzioni alternative di cui sono a conoscenza.

È anche documentato sull'articolo di Eric Meyer: Un-fixed Fixed Elements con CSS Transforms .


Grazie, non avevo notato che la specifica effettiva aveva quell'informazione ..... Immagino di aver ottenuto l'equivalente della risposta matematica: "per definizione" :)
Juan Carlos Moreno

3
@INT, non credo che ci sarà una soluzione per questo. Esiste un caso d'uso importante per non consentire soluzioni alternative: l'input fornito dall'utente potrebbe potenzialmente coprire i controlli al di fuori dell'area designata (si pensi a un'e-mail dannosa che aggiunge opzioni alla barra degli strumenti di Gmail). La soluzione migliore sarebbe quella di evitare trasformazioni per il momento, se hai intenzione di usare riparato dall'interno di esso.
saml

1
Non impostare l'attributo top CSS su qualunque window.scrollHeight sia funzionante? Potrebbe anche essere necessario posizionarlo assolutamente, ma qualcosa del genere dovrebbe essere fattibile, no? (troppo pigro per testarlo in questo momento)
Brad Orego

@bradorego avevi ragione, ho appena aggiunto il codice che ho usato.
UzumakiDev

Per quanto ne so, questo è ancora in evoluzione nelle specifiche. Vedi Bug 16328 - L'uso di "blocco contenente" non corrisponde alla definizione CSS2.1 .
terzo

13

Ho avuto uno sfarfallio sul mio navigatore fisso superiore quando gli elementi nella pagina stavano usando la trasformazione, il seguente applicato al mio navigatore superiore ha risolto il problema di salto / sfarfallio:

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

Grazie a questa risposta su SO


12

Come ha suggerito Bradoergo, basta prendere la finestra scrollTope aggiungerla in cima alla posizione assoluta come:

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);

Questo ha funzionato per me comunque.


3
Funziona! ma invece di legare a "finestra", ho dovuto legarmi al div che stava scorrendo. Inoltre, l'elemento fisso lampeggia.
treno,

Cosa deve fare jQuery qui?
FlorianB,

Questo avrebbe potuto farlo, ma come menzionato da @train, lampeggia.
Etienne Dupuis,

Sì, questo non si aggiorna abbastanza velocemente da essere abbastanza pulito per il mio uso: - / buona idea però
reid

Questa è una brutta pratica, non fare cambiamenti di stile con js
Wannes,

4

In Firefox e Safari puoi usare position: sticky;invece di position: fixed;ma non funzionerà in altri browser. Per questo è necessario JavaScript.


2
Il posizionamento appiccicoso è un ibrido di posizionamento relativo e fisso ed è davvero sperimentale , consiglio vivamente di evitarlo, poiché non è ancora standard.
Farside,

1
AFAIK su Firefox e Safari puoi semplicemente usare position:fixede funzionerebbe comunque come previsto.
Oriadam,

@oriadam no, ho il problema quando il genitore usa translate3d e la posizione fissa dei bambini vola in alcuni casi. Proverò a utilizzarlo stickymentre è già supportato dai principali browser: caniuse.com/#feat=css-sticky
Lukas Liesis

stickypotrebbe essere una soluzione, funziona con un browser moderno.
circa

3

Secondo me, il metodo migliore per affrontare questo è applicare la stessa traduzione, ma spezzare i bambini che devono essere riparati dal loro elemento genitore (tradotto); e quindi applicare il traduttore a un div all'interno del position: fixedwrapper.

I risultati sembrano simili a questo (nel tuo 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/

Anche se questo potrebbe non essere l'ideale per alcuni casi d'uso, in genere se stai riparando un div probabilmente non ti interesserebbe di quale elemento sia il suo genitore / dove cade nell'albero ereditario nel tuo DOM e sembra risolvere la maggior parte del mal di testa - pur consentendo comunque ad entrambi translatee position: fixeddi vivere in (relativa) armonia.


0

Ho riscontrato lo stesso problema. L'unica differenza è che il mio elemento con 'position: fixed' aveva le sue proprietà di stile 'top' e 'left' impostate da JS. Quindi sono stato in grado di applicare una correzione:

var oRect = oElement.getBoundingClientRect();

L'oggetto oRect conterrà le coordinate superiore e sinistra reali (relative alla porta di visualizzazione). Quindi puoi regolare le tue attuali proprietà oElement.style.top e oElement.style.left.


Funziona su IE e Chrome, ma non sul browser Android standard. La sinistra è un numero ma viene sempre disegnato nella posizione 0
Adaptabi

0

Ho una barra laterale fuori tela che utilizza -webkit-transform: translate3d. Ciò mi impediva di posizionare un piè di pagina fisso sulla pagina. Ho risolto il problema indirizzando una classe nella pagina html che viene aggiunta al tag all'inizializzazione della barra laterale e quindi scrivendo un CSS: non qualificatore per dichiarare "-webkit-transform: none;" al tag html quando quella classe non è presente sul tag html. Spero che questo aiuti qualcuno là fuori con lo stesso problema!


0

Prova ad applicare la trasformazione opposta all'elemento figlio:

<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>

0

Aggiungi una classe dinamica mentre l'elemento si trasforma. $('#elementId').addClass('transformed'). Quindi continua a dichiarare in 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 
}

poi

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

poi

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

Ora, position: fixedquando forniti con a tope z-indexvalori di proprietà su un elemento figlio, funzionano bene e rimangono fissi fino a quando l'elemento genitore si trasforma. Quando la trasformazione viene ripristinata, l'elemento figlio viene nuovamente visualizzato come risolto. Questo dovrebbe alleviare la situazione se stai effettivamente utilizzando una barra laterale di navigazione che si apre e si chiude con un clic, e hai un set di schede che dovrebbe rimanere appiccicoso mentre scorri la pagina.


-1

Un modo per gestirlo è applicare la stessa trasformazione all'elemento fisso:

<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>

1
Il bug di IE non esiste al primo posto
oriadam,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.