'transform3d' não está funcionando com a posição: filhos fixos

140

Eu tenho uma situação em que, em circunstâncias normais de CSS, uma div fixa seria posicionada exatamente onde é especificada ( top:0px, left:0px).

Isso não parece ser respeitado se eu tiver um pai que tenha uma conversão translate3d. Não estou vendo alguma coisa? Eu tentei outras opções de transformação e estilo de transformação do webkit, mas não tive sorte.

Anexei um JSFiddle com um exemplo em que eu esperava que a caixa amarela estivesse no canto superior da página e não dentro do elemento do contêiner.

Você pode encontrar abaixo uma versão simplificada do 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>

Como posso fazer o translate3d funcionar com crianças de posição fixa?

Juan Carlos Moreno
fonte
O mesmo problema também acontece com o filtro: stackoverflow.com/q/52937708/8620333 #
Temani Afif

Respostas:

196

Isso ocorre porque ele transformcria um novo sistema de coordenadas local, conforme a especificação do W3C :

No espaço de nome HTML, qualquer valor que não seja nonea transformação resulta na criação de um contexto de empilhamento e de um bloco contendo. O objeto atua como um bloco de contenção para descendentes fixos posicionados.

Isso significa que o posicionamento fixo fica fixo no elemento transformado, e não na viewport.

Atualmente, não há uma solução alternativa que eu saiba.

Também está documentado no artigo de Eric Meyer: Desinstalando elementos fixos com transformações CSS .

saml
fonte
Obrigado, eu não tinha notado que a especificação real tinha essa informação ..... eu acho que eu tenho o equivalente à resposta matemática: "por definição" :)
Juan Carlos Moreno
3
@INT, acho que não haverá uma solução alternativa para isso. Há um caso de uso importante para não permitir soluções alternativas: a entrada fornecida pelo usuário pode cobrir controles fora da área designada (pense em um email malicioso adicionando opções à barra de ferramentas do gmail). A melhor solução seria evitar as transformações por enquanto, se você for usar reparado de dentro dela.
saml 26/08/13
1
Não definir o atributo top CSS como qualquer janela.scrollHeight funciona? Você pode ter que posicioná-lo absolutamente também, mas algo assim deve ser factível, não? (preguiça de realmente testar agora)
Brad Orego
@bradorego você estava certo, acabei de adicionar o código que usei.
UzumakiDev 31/01
Isso ainda está em fluxo nas especificações, tanto quanto eu posso dizer. Veja o Bug 16328 - O uso do "bloco contendo" não corresponde à definição CSS2.1 .
Terceira-
13

Tive uma cintilação na minha navegação superior fixa quando os itens da página estavam usando transformação, o seguinte aplicado à minha navegação superior resolveu o problema de salto / cintilação:

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

Graças a esta resposta no SO

rob.m
fonte
12

Como Bradoergo sugeriu, basta pegar a janela scrollTope adicioná-la ao topo da posição absoluta, 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);

Isso funcionou para mim de qualquer maneira.

UzumakiDev
fonte
3
Funciona! mas em vez de vincular a "janela", tive que vincular à div que estava rolando. Além disso, o elemento fixo pisca.
train
O que o jQuery tem que fazer aqui?
FlorianB 07/07/16
Isso poderia ter acontecido, mas, como o @train mencionado, ele pisca.
Etienne Dupuis
Sim, isso não atualizar perto rápido o suficiente para ser bastante limpo para o meu uso: - / boa idéia tho
Reid
Esta é uma prática muito ruim, não faça mudanças de estilo com js #
2844
4

No Firefox e Safari, você pode usar em position: sticky;vez de, position: fixed;mas não funcionará em outros navegadores. Para isso você precisa de javascript.

Dušan
fonte
2
O posicionamento fixo é um híbrido de posicionamento relativo e fixo, e é realmente experimental , eu recomendo evitar isso, pois ainda não é padrão.
Farside
1
AFAIK no Firefox e Safari, você pode simplesmente usar position:fixede funcionaria como esperado de qualquer maneira.
oriadam 15/09/16
@oriadam não, eu tenho o problema quando o pai usa o translate3d e a posição fixa das crianças está voando em alguns casos. Tentará usar stickyenquanto ele já apoiado por grandes navegadores: caniuse.com/#feat=css-sticky
Lukas Liesis
stickypode ser uma solução, funciona no navegador moderno.
Aboutqx 17/05/19
3

Na minha opinião, o melhor método para lidar com isso é aplicar a mesma conversão, mas interromper os filhos que precisam ser corrigidos do elemento pai (traduzido); e aplique a conversão a uma div dentro do position: fixedwrapper.

Os resultados são mais ou menos assim (no seu 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/

Embora isso possa não ser o ideal para alguns casos de uso, normalmente, se você estiver corrigindo uma div, provavelmente se preocupará menos com qual elemento é seu pai / onde ele fica na árvore de herança no seu DOM e parece resolver a maior parte da dor de cabeça. - enquanto ainda permite ambos translatee position: fixedviver em harmonia (relativa).

reid
fonte
0

Encontrei o mesmo problema. A única diferença é que meu elemento com 'position: fixed' tinha suas propriedades de estilo 'top' e 'left' definidas em JS. Então, pude aplicar uma correção:

var oRect = oElement.getBoundingClientRect();

O objeto oRect conterá coordenadas reais e superiores (em relação à porta de visualização). Assim, você pode ajustar suas propriedades reais oElement.style.top e oElement.style.left.

Mike Dobrin
fonte
Isso funciona no IE e no Chrome, mas não no navegador padrão do Android. A esquerda é um número, mas é sempre sorteada na posição 0
Adaptabi 23/08
0

Eu tenho uma barra lateral fora da tela que usa -webkit-transform: translate3d. Isso estava me impedindo de colocar um rodapé fixo na página. Resolvi o problema direcionando uma classe na página html que é adicionada à tag na inicialização da barra lateral e, em seguida, escrevendo um qualificador css: not no estado "-webkit-transform: none;" para a tag html quando essa classe não estiver presente na tag html. Espero que isso ajude alguém por aí com esse mesmo problema!

WeisbergWeb
fonte
0

Tente aplicar a conversão oposta ao elemento filho:

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

Adicione uma classe dinâmica enquanto o elemento se transforma. $('#elementId').addClass('transformed'). Em seguida, declare em 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 
}

então

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

então

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

Agora, position: fixedquando fornecidos com os valores de propriedade a tope z-indexem um elemento filho, apenas funcione bem e permaneça fixo até que o elemento pai se transforme. Quando a transformação é revertida, o elemento filho aparece como corrigido novamente. Isso deve facilitar a situação se você estiver realmente usando uma barra lateral de navegação que abre e fecha com um clique e você tem um conjunto de guias que deve permanecer fixo ao rolar a página.

mr.G
fonte
-1

Uma maneira de lidar com isso é aplicar a mesma transformação ao elemento fixo:

<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
fonte
1
No IE, o bug não existe em primeiro lugar
oriadam 15/09/16