'transform3d' funktioniert nicht mit Position: feste Kinder

140

Ich habe eine Situation, in der unter normalen CSS-Umständen ein fester Div genau dort positioniert wird, wo er angegeben ist ( top:0px, left:0px).

Dies scheint nicht respektiert zu werden, wenn ich ein Elternteil habe, das eine translate3d-Transformation hat. Sehe ich nichts Ich habe andere Webkit-transformierte Stil- und Ursprungsoptionen ausprobiert, hatte aber kein Glück.

Ich habe eine JSFiddle mit einem Beispiel angehängt, bei dem ich erwartet hätte, dass sich das gelbe Feld in der oberen Ecke der Seite befindet und nicht innerhalb des Containerelements.

Unten finden Sie eine vereinfachte Version der Geige:

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

Wie kann ich translate3d mit fest positionierten Kindern zum Laufen bringen?

Juan Carlos Moreno
quelle
Das gleiche Problem tritt auch beim Filter auf: stackoverflow.com/q/52937708/8620333
Temani Afif

Antworten:

196

Dies liegt daran, dass transformein neues lokales Koordinatensystem gemäß W3C-Spezifikation erstellt wird :

Im HTML-Namespace führt jeder andere Wert als nonefür die Transformation dazu, dass sowohl ein Stapelkontext als auch ein enthaltender Block erstellt werden. Das Objekt fungiert als enthaltender Block für fest positionierte Nachkommen.

Dies bedeutet, dass die feste Positionierung eher auf das transformierte Element als auf das Ansichtsfenster festgelegt wird.

Derzeit ist mir keine Problemumgehung bekannt.

Es ist auch in Eric Meyers Artikel dokumentiert: Aufheben fester Elemente mit CSS-Transformationen .

saml
quelle
Danke, ich hatte nicht bemerkt, dass die tatsächliche Spezifikation diese Informationen enthielt ..... Ich glaube, ich habe das Äquivalent zur mathematischen Antwort erhalten: "per Definition" :)
Juan Carlos Moreno
3
@INT, ich glaube nicht, dass es dafür eine Problemumgehung geben wird. Es gibt einen wichtigen Anwendungsfall, um Problemumgehungen nicht zuzulassen: Vom Benutzer bereitgestellte Eingaben können möglicherweise Steuerelemente außerhalb des festgelegten Bereichs abdecken (denken Sie an eine böswillige E-Mail, die Optionen zur Google Mail-Symbolleiste hinzufügt). Die beste Problemumgehung wäre, vorerst Transformationen zu vermeiden, wenn Sie Fixed von innen verwenden.
Saml
1
Würde es nicht funktionieren, das CSS-Top-Attribut auf ein beliebiges window.scrollHeight zu setzen? Sie müssen es vielleicht auch unbedingt positionieren, aber so etwas sollte machbar sein, nein? (zu faul, um jetzt tatsächlich zu testen)
Brad Orego
@radorego Sie hatten Recht, ich habe gerade den Code hinzugefügt, den ich verwendet habe.
UzumakiDev
Soweit ich das beurteilen kann, ist dies in der Spezifikation immer noch im Fluss. Siehe Fehler 16328 - Die Verwendung von "enthaltendem Block" stimmt nicht mit der CSS2.1-Definition überein .
Thirdender
13

Ich hatte ein Flackern auf meinem festen Top-Navi, als Elemente auf der Seite transformiert wurden. Folgendes, das auf mein Top-Navi angewendet wurde, löste das Problem mit dem Springen / Flackern:

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

Dank dieser Antwort auf SO

rob.m
quelle
12

Wie Bradoergo vorgeschlagen hat, holen Sie sich einfach das Fenster scrollTopund fügen Sie es der absoluten Position oben hinzu:

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

Das hat bei mir sowieso funktioniert.

UzumakiDev
quelle
3
Es klappt! aber anstatt an "window" zu binden, musste ich mich an das div binden, das gescrollt wurde. Auch das feste Element flackert.
Zug
Was muss jQuery hier tun?
FlorianB
Dies hätte es tun können, aber wie @train erwähnt, flackert es.
Etienne Dupuis
Ja, dieses Update nicht in der Nähe schnell genug sauber genug für meine Nutzung zu sein: - / gute Idee tho
reid
Dies ist eine sehr schlechte Praxis, machen Sie keine Stiländerungen mit js
Wannes
4

In Firefox und Safari können Sie position: sticky;anstelle von verwenden, position: fixed;aber es funktioniert nicht in anderen Browsern. Dafür benötigen Sie Javascript.

Dušan
quelle
2
Sticky Positioning ist eine Mischung aus relativer und fester Positionierung und sehr experimentell . Ich würde dringend empfehlen, dies zu vermeiden, da es noch nicht Standard ist.
Farside
1
AFAIK auf Firefox und Safari können Sie einfach verwenden position:fixedund es würde sowieso wie erwartet funktionieren.
Oriadam
@oriadam nein, ich habe das Problem, wenn die Eltern translate3d verwenden und die feste Position der Kinder in einigen Fällen herumfliegt. Ich werde versuchen, es zu verwenden, stickysolange es bereits von den wichtigsten Browsern unterstützt wird: caniuse.com/#feat=css-sticky
Lukas Liesis
stickykann eine Lösung sein, es funktioniert bei modernen Browsern.
ungefähr
3

Meiner Meinung nach besteht die beste Methode, um damit umzugehen, darin, dieselbe Übersetzung anzuwenden, aber Kinder, die repariert werden müssen, aus ihrem übergeordneten (übersetzten) Element herauszubrechen. und wenden Sie dann die Übersetzung auf ein Div im position: fixedWrapper an.

Die Ergebnisse sehen ungefähr so ​​aus (in Ihrem Fall):

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

Während dies für einige Anwendungsfälle möglicherweise nicht ideal ist, ist es Ihnen normalerweise weniger wichtig, welches Element übergeordnet ist / wo es in den Vererbungsbaum in Ihrem DOM fällt, und es scheint den größten Teil der Kopfschmerzen zu lösen, wenn Sie ein Div reparieren - während man beides erlaubt translateund position: fixedin (relativer) Harmonie lebt.

Reid
quelle
0

Ich bin auf dasselbe Problem gestoßen. Der einzige Unterschied besteht darin, dass für mein Element mit 'position: fixed' die Stileigenschaften 'top' und 'left' von JS festgelegt wurden. So konnte ich einen Fix anwenden:

var oRect = oElement.getBoundingClientRect();

oRect-Objekt enthält echte (relativ zum Ansichtsfenster) obere und linke Koordinaten. So können Sie Ihre tatsächlichen Eigenschaften oElement.style.top und oElement.style.left anpassen.

Mike Dobrin
quelle
Dies funktioniert unter IE und Chrome, jedoch nicht unter Android-Standardbrowser. Das linke ist eine Zahl, aber es wird immer auf der Position 0 gezeichnet
Adaptabi
0

Ich habe eine Seitenleiste außerhalb der Leinwand, die -webkit-transform verwendet: translate3d. Dies hinderte mich daran, eine feste Fußzeile auf der Seite zu platzieren. Ich habe das Problem behoben, indem ich auf eine Klasse auf der HTML-Seite abzielte, die bei der Initialisierung der Seitenleiste zum Tag hinzugefügt wurde, und dann ein CSS: not-Qualifikationsmerkmal mit dem Status "-webkit-transform: none;" zum HTML-Tag, wenn diese Klasse im HTML-Tag nicht vorhanden ist. Hoffe, das hilft jemandem da draußen mit dem gleichen Problem!

WeisbergWeb
quelle
0

Versuchen Sie, eine entgegengesetzte Transformation auf das untergeordnete Element anzuwenden:

<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.
quelle
0

Fügen Sie eine dynamische Klasse hinzu, während sich das Element transformiert. $('#elementId').addClass('transformed'). Dann deklarieren Sie 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 
}

dann

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

dann

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

Nun , position: fixedwenn sie mit einem vorgesehenen topund z-indexEigenschaftswert für ein untergeordnetes Element nur gut funktionieren und Aufenthalt festgelegt , bis der übergeordneten Element verwandelt. Wenn die Umwandlung zurückgesetzt wird, wird das untergeordnete Element wieder als fest angezeigt. Dies sollte die Situation verschlechtern, wenn Sie tatsächlich eine Navigationsseitenleiste verwenden, die beim Klicken um- und geschlossen werden kann, und Sie haben eine Registerkarte, die beim Scrollen auf der Seite klebrig bleiben sollte.

mr.G.
quelle
-1

Eine Möglichkeit, damit umzugehen, besteht darin, dieselbe Transformation auf das feste Element anzuwenden:

<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
quelle
1
On IE Fehler existiert nicht an erster Stelle
Oriadam