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

142

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

Похоже, это не соблюдается, если у меня есть родительский объект с преобразованием translate3d. Я чего-то не вижу? Я пробовал другие варианты webkit-transform, такие как style и transform origin, но мне не повезло.

Я прикрепил 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>

Как заставить translate3d работать с фиксированными дочерними элементами?

Хуан Карлос Морено
источник
То же проблема возникает с фильтром тоже: stackoverflow.com/q/52937708/8620333
Феманитяне Afif

Ответы:

200

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

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

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

В настоящее время мне известно об обходном пути.

Это также задокументировано в статье Эрика Мейера: « Удаление фиксированных элементов с помощью преобразований CSS» .

самл
источник
Спасибо, я не заметил, что в фактической спецификации была эта информация… Думаю, я получил эквивалент математического ответа: «по определению» :)
Хуан Карлос Морено
3
@INT, я не думаю, что это будет обходное решение. Существует один из основных вариантов использования обходных путей: вводимые пользователем данные могут потенциально покрывать элементы управления за пределами их назначенной области (подумайте, что вредоносное электронное письмо добавляет параметры на панель инструментов Gmail). Лучшим обходным решением было бы на время избегать преобразований, если вы собираетесь использовать фиксированный внутри него.
saml
1
Не установил бы атрибут CSS top для того, что работает window.scrollHeight? Возможно, вам также придется полностью позиционировать его, но что-то вроде этого должно быть выполнимым, не так ли? (слишком ленив, чтобы тестировать прямо сейчас)
Брэд Орего
@bradorego, ты был прав, я просто добавил код, который использовал.
UzumakiDev
Насколько я могу судить, это все еще находится в стадии разработки в спецификации. См. Ошибка 16328 - использование «содержащего блока» не соответствует определению CSS2.1 .
thirdender
13

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

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

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

rob.m
источник
12

Как предложил Bradoergo, просто возьмите окно 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);

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

УзумакиДев
источник
3
Оно работает! но вместо привязки к «окну» мне пришлось привязаться к прокручивающемуся div. Также мерцает фиксированный элемент.
поезд
Что здесь должен делать jQuery?
FlorianB 07
Это могло бы сделать это, но, как упоминал @train, оно мерцает.
Этьен Дюпюи
Да, это не обновляется достаточно быстро, чтобы быть достаточно чистым для моего использования: - / хорошая идея, хотя
reid
Это очень плохая практика, не меняйте стиль с помощью js
Ваннес,
5

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

Душан
источник
2
Липкое позиционирование - это гибрид относительного и фиксированного позиционирования, и оно действительно экспериментальное , я настоятельно рекомендую избегать этого, поскольку оно еще не стандартно.
Farside
1
AFAIK в Firefox и Safari вы можете просто использовать, position:fixedи в любом случае он будет работать так, как ожидалось.
oriadam
@oriadam нет, у меня проблема, когда родитель использует translate3d, а фиксированная позиция детей в некоторых случаях летает. Попробую использовать, stickyпока он уже поддерживается основными браузерами: caniuse.com/#feat=css-sticky
Лукас Лисис
stickyможет быть решением, он работает в современном браузере.
aboutqx
3

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

Рейд
источник
0

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

var oRect = oElement.getBoundingClientRect();

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

Майк Добрин
источник
Это работает в IE и Chrome, но не в стандартном браузере Android. Слева - число, но оно всегда отображается на позиции 0
Adaptabi
0

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

WeisbergWeb
источник
0

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

<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

Добавьте динамический класс во время преобразования элемента. $('#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просто работают нормально и остаются фиксированными до тех пор, пока родительский элемент не преобразуется. Когда преобразование отменяется, дочерний элемент снова появляется как фиксированный. Это должно облегчить ситуацию, если вы на самом деле используете боковую панель навигации, которая переключается на открытие и закрытие при нажатии, и у вас есть набор вкладок, который должен оставаться липким при прокрутке страницы вниз.

г-н Г
источник
-1

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

<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
источник
1
В IE ошибка не существует в первую очередь
oriadam