„transform3d” nie działa z pozycją: naprawione dzieci


140

Mam sytuację, w której w normalnych warunkach CSS ustalony element div zostałby umieszczony dokładnie tam, gdzie jest określony ( top:0px, left:0px).

Wydaje się, że nie jest to respektowane, jeśli mam rodzica, który ma transformate3d. Czy ja czegoś nie widzę? Wypróbowałem inne opcje transformacji webkit, takie jak style i transform origin opcje, ale nie miałem szczęścia.

I dołączony JSFiddle z przykładu I gdzie oczekiwany żółtą pole być w narożniku górnej strony, a nie wewnątrz elementu pojemnika.

Poniżej znajduje się uproszczona wersja skrzypiec:

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

Jak mogę sprawić, by translate3d działało z dziećmi o ustalonej pozycji?


Ten sam problem występuje również z filtrem: stackoverflow.com/q/52937708/8620333
Temani Afif

Odpowiedzi:


196

Dzieje się tak, ponieważ transformtworzy nowy lokalny układ współrzędnych, zgodnie ze specyfikacją W3C :

W przestrzeni nazw HTML każda wartość inna niż nonedla transformacji powoduje utworzenie zarówno kontekstu stosowego, jak i zawierającego blok. Obiekt działa jako blok zawierający elementy potomne o ustalonej pozycji.

Oznacza to, że ustalone położenie zostaje ustalone na przekształconym elemencie, a nie na rzutni.

Obecnie nie ma rozwiązania, o którym jestem świadomy.

Jest to również udokumentowane w artykule Erica Meyera: Un-Fixing Fixed Elements with CSS Transforms .


Dzięki, nie zauważyłem, że rzeczywista specyfikacja zawiera te informacje ..... Wydaje mi się, że otrzymałem odpowiednik odpowiedzi matematycznej: „z definicji” :)
Juan Carlos Moreno

3
@INT, nie sądzę, aby można było to obejść. Istnieje poważny przypadek użycia niepozwalania na obejścia: dane wprowadzane przez użytkownika mogą potencjalnie obejmować kontrole poza wyznaczonym obszarem (pomyśl o złośliwym e-mailu dodającym opcje do paska narzędzi Gmaila). Najlepszym obejściem byłoby tymczasowe unikanie przekształceń, jeśli zamierzasz używać naprawionych od wewnątrz.
saml

1
Czy ustawienie górnego atrybutu CSS na dowolny parametr window.scrollHeight nie zadziała? Być może będziesz musiał absolutnie ustawić to również, ale coś takiego powinno być wykonalne, prawda? (zbyt leniwy, żeby teraz testować)
Brad Orego

@bradorego miałeś rację, właśnie dodałem kod, którego użyłem.
UzumakiDev

O ile wiem, to wciąż się zmienia w specyfikacji. Zobacz błąd 16328 - użycie „zawierającego blok” nie pasuje do definicji CSS2.1 .
trzecia osoba

13

Miałem migotanie na moim stałym górnym pasku nawigacyjnym, gdy elementy na stronie korzystały z przekształcenia, następujące elementy zastosowane do mojej górnej nawigacji rozwiązały problem przeskakiwania / migotania:

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

Dzięki tej odpowiedzi na SO


12

Jak zasugerował Bradoergo, po prostu weź okno scrollTopi dodaj je do absolutnej górnej pozycji, na przykład:

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

To i tak działało dla mnie.


3
To działa! ale zamiast wiązać się z „oknem”, musiałem połączyć się z przewijanym elementem div. Ponadto nieruchomy element miga.
pociąg

Co tu robi jQuery?
FlorianB,

Mogło to zrobić, ale jak wspomniał @train, migocze.
Etienne Dupuis

Tak, to nie aktualizuje się wystarczająco szybko, aby było wystarczająco czyste do mojego użytku: - / chociaż dobry pomysł
reid

To bardzo zła praktyka, nie zmieniaj stylu za pomocą js
Wannes

4

W przeglądarkach Firefox i Safari można używać position: sticky;zamiast, position: fixed;ale nie będzie działać w innych przeglądarkach. Do tego potrzebny jest javascript.


2
Lepkie pozycjonowanie to hybryda pozycjonowania względnego i ustalonego i jest naprawdę eksperymentalne , bardzo polecam tego unikać, ponieważ nie jest jeszcze standardowe.
Farside

1
AFAIK w Firefoksie i Safari możesz po prostu użyć, position:fixeda i tak będzie działać zgodnie z oczekiwaniami.
oriadam

@oriadam nie, mam problem, gdy rodzic używa translate3d, a stała pozycja dzieci w niektórych przypadkach leci dookoła. Spróbuje użyć, stickygdy jest już obsługiwany przez główne przeglądarki: caniuse.com/#feat=css-sticky
Lukas Liesis

stickymoże być rozwiązaniem, działa w nowoczesnej przeglądarce.
okołoqx

3

Moim zdaniem najlepszą metodą radzenia sobie z tym jest zastosowanie tego samego tłumaczenia, ale zerwanie dzieci, które muszą zostać naprawione, z ich elementu nadrzędnego (przetłumaczonego); a następnie zastosuj translację do elementu div wewnątrz position: fixedopakowania.

Wyniki wyglądają mniej więcej tak (w twoim przypadku):

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

Chociaż może to nie być idealne w niektórych przypadkach użycia, zazwyczaj jeśli naprawiasz element div, prawdopodobnie nie obchodzi Cię, który element jest jego elementem nadrzędnym / gdzie znajduje się w drzewie dziedziczenia w Twoim DOM i wydaje się, że rozwiązuje większość problemów - jednocześnie pozwalając jednocześnie na jedno translatei drugie position: fixedw (względnej) harmonii.


0

Natknąłem się na ten sam problem. Jedyną różnicą jest to, że mój element z atrybutem „position: fixed” miał ustawione właściwości stylu „top” i „left” z JS. Więc udało mi się zastosować poprawkę:

var oRect = oElement.getBoundingClientRect();

Obiekt oRect będzie zawierał rzeczywiste (względem portu widoku) górne i lewe współrzędne. Możesz więc dostosować swoje rzeczywiste właściwości oElement.style.top i oElement.style.left.


Działa to w IE i Chrome, ale nie w standardowej przeglądarce Androida. Lewa to liczba, ale zawsze losowana na pozycji 0
Adaptabi

0

Mam pasek boczny poza płótnem, który używa -webkit-transform: translate3d. To uniemożliwiało mi umieszczenie stałej stopki na stronie. Rozwiązałem problem, kierując na klasę na stronie html, która jest dodawana do tagu podczas inicjalizacji paska bocznego, a następnie pisząc kwalifikator css: not o stanie „-webkit-transform: none;” do tagu html, gdy tej klasy nie ma w tagu html. Mam nadzieję, że to pomoże komuś z tym samym problemem!


0

Spróbuj zastosować odwrotną transformację do elementu potomnego:

<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

Dodaj klasę dynamiczną podczas transformacji elementu. $('#elementId').addClass('transformed'). Następnie zadeklaruj w 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 
}

następnie

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

następnie

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

Teraz, position: fixedgdy zostaną dostarczone z wartościami właściwości a topi z-indexelementu podrzędnego, po prostu działają dobrze i pozostają stałe, dopóki element nadrzędny nie ulegnie transformacji. Kiedy transformacja zostanie cofnięta, element potomny wyskakuje jako naprawiony ponownie. Powinno to złagodzić sytuację, jeśli faktycznie używasz bocznego paska nawigacji, który otwiera się i zamyka po kliknięciu, a masz zestaw zakładek, który powinien pozostać lepki podczas przewijania strony.


-1

Jednym ze sposobów rozwiązania tego problemu jest zastosowanie tej samej transformacji do stałego elementu:

<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
Na IE błąd nie istnieje na pierwszym miejscu
oriadam
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.