'transform3d' не работает с позицией: фиксированные дети

У меня есть ситуация, когда в нормальных условиях CSS фиксированный div будет расположен именно там, где он указан (top:0px, left:0px).

Это, кажется, не соблюдается, если у меня есть родитель, у которого есть translate3d преобразование. Я что-то не вижу? Я пробовал другие webkit-трансформации, такие как стиль и параметры трансформации источника, но мне не повезло.

Я приложил JSFiddle с примером, где я ожидал, что желтая рамка будет в верхнем углу страницы, а не внутри элемента контейнера.

Ниже вы можете найти упрощенную версию скрипки:

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

Ответы

Ответ 1

Это связано с тем, что transform создает новую локальную систему координат по спецификации W3C:

В пространстве имен HTML любое значение, отличное от none для преобразования, приводит к созданию как стекового контекста, так и содержащего блока. Объект действует как содержащий блок для фиксированных позиционированных потомков.

Это означает, что фиксированное позиционирование становится привязанным к преобразованному элементу, а не к окну просмотра.

В настоящий момент я не знаю, о чем я знаю.

Также описывается статья Эрика Мейера: Исправление фиксированных элементов с помощью CSS-преобразований.

Ответ 2

У меня было мерцание на моем фиксированном верхнем навигаторе, когда элементы на странице использовали преобразование, следующее применимо к моему верхнему навигатору, решило проблему с прыганием/мерцанием:

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

Благодаря этому ответу на SO

Ответ 3

Как предложил Брадоерго, просто оставьте окно scrollTop и добавьте его в верхнюю позицию абсолютного положения, например:

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

Все это сработало для меня.

Ответ 4

В Firefox и Safari вы можете использовать position: sticky; вместо position: fixed;, но он не будет работать в других браузерах. Для этого вам нужен javascript.

Ответ 5

На мой взгляд, лучший способ справиться с этим - применить тот же самый перевод, но отделить дочерние элементы, которые должны быть зафиксированы от их родительского (переведенного) элемента; и затем примените перевод к div внутри position: fixed обертка.

Результаты выглядят примерно так (в вашем случае):

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

Хотя это может не быть идеальным для некоторых случаев использования, обычно, если вы исправляете div, вам, возможно, будет безразлично, какой элемент является его родителем/где он находится в дереве наследования в вашем DOM, и, похоже, он решает большую часть головной боли - в то же время позволяя как translate и translate position: fixed жить в (относительной) гармонии.

Ответ 6

Я столкнулся с той же проблемой. Единственное различие заключается в том, что мой элемент с "position: fixed" имел свои свойства стиля "top" и "left", установленные из JS. Поэтому я смог применить исправление:

var oRect = oElement.getBoundingClientRect();

Объект oRect будет содержать реальные (относительно порта представления) верхние и левые координаты. Таким образом, вы можете настроить свои фактические свойства oElement.style.top и oElement.style.left.

Ответ 7

У меня такая же проблема, и я считаю, что вокруг это работает. Я использую snap.js, и я хочу, чтобы один из дочерних div контейнера содержимого был зафиксирован на его позиции. Однако, когда ящик открывается, JavaScript запускает свойство transform: translate3d для родительского контейнера, и это также влияет на фиксированный дочерний элемент (фиксированный элемент перемещается вместе со своим родителем и остается фиксированным в новой позиции).

С учетом сказанного фиксированное свойство становится частично бесполезным. Чтобы решить эту проблему, может быть добавлен прослушиватель событий, который будет запускать отдельный tranform: translate3d для фиксированного дочернего div. И направление этого перевода должно быть противоположно родительскому преобразованию: translate3d.

Единственная проблема заключается в том, что я не знаю, как ее написать, и было бы здорово, если бы кто-то взял на нее удар.

Ответ 8

У меня есть боковая панель с холстом, которая использует -webkit-transform: translate3d. Это мешало мне помещать фиксированный нижний колонтитул на страницу. Я решил проблему, настроив класс на html-странице, который добавлен в тег при инициализации боковой панели, а затем написал css: not qualifier, чтобы указать "-webkit-transform: none;" в тег html, когда этот класс отсутствует в теге html. Надеюсь, это поможет кому-то там с этой же проблемой!

Ответ 9

Попробуйте применить противоположное преобразование к дочернему элементу:

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

Ответ 10

Добавьте динамический класс, пока элемент трансформируется. $('#elementId').addClass('transformed'). Затем продолжайте объявлять в 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 
}

затем

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

затем

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

Теперь position: fixed если для дочернего элемента заданы значения свойств top и z-index просто работают нормально и остаются неизменными до преобразования родительского элемента. Когда преобразование отменено, дочерний элемент снова появляется как исправлено. Это должно облегчить ситуацию, если вы фактически используете боковую панель навигации, которая включает и закрывает при нажатии, и у вас есть набор вкладок, который должен оставаться липким при прокрутке страницы вниз.

Ответ 11

Один из способов борьбы с этим - применить одно и то же преобразование к фиксированному элементу:

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

Ответ 12

Если вы работаете на мобильном телефоне с меню offcanvas, возможно, этот код вам поможет.

    $('#toggle-button').click(function () {
    slideout.toggle();

    // Sticky menu with off canvas menu (for mobile)
    var isMenuDisplaced = $('.sticky-menu').hasClass('is-displaced');

    if (isMenuDisplaced === false) {
        $('.sticky-menu').addClass('is-displaced');
        var scrollTopPosition = $(window).scrollTop();
        $('.sticky-menu').css('position', 'absolute');
        $('.sticky-menu').css('top', scrollTopPosition + 'px');
    }

    else {
        window.setTimeout(function () {
            $('.sticky-menu').removeClass('is-displaced');
            $('.sticky-menu').css('position', 'fixed');
            $('.sticky-menu').css('top', 0);
        }, 400);
    }


})