Абсолютно позиционированные плавающие заголовки Jitter в Safari

У меня есть простой JSFiddle одного плавающего заголовка здесь:

http://jsfiddle.net/zT9KQ/

В основном это использует translate3d для запуска в графическом процессоре, а аппаратное ускорение плавающего заголовка, чтобы его можно было сделать более плавно. Заголовок вздрагивает в последнем Safari, но в последних браузерах Chrome, FF и Opera получается отлично. Фактический код, на который это влияет (код, который подстегнул этот вопрос), - это код, который я написал, который нельзя публиковать публично, но работает аналогичным образом, когда позиционирование fixed, к сожалению, не является допустимым решением.

Я пробовал:

  • Установка свойства backface-visibility CSS в none.
  • Установка свойства perspective CSS в 1000.
  • Игра с requestAnimationFrame во время логики анимации.
  • Дросселирование обратного вызова события прокрутки.
  • Настройка преобразования translateZ на нечто большее, чем 0px.

Но ничто из этого не сработало (или, по крайней мере, кажется разумным предположить, что GPU зашел, но дрожание сохраняется). Я заметил, что два вопроса уже открыты, которые идентичны тому, который я поднимаю, но никто не ответил на них:

Это известная ошибка? Есть ли отверстие для производительности, которое я не запечатываю?

ИЗМЕНИТЬ

Я получаю много вопросов относительно того, почему position: fixed не является допустимым вариантом. Чтобы прямо ответить Антонию на сам вопрос:

Я не эмулирую/не изобретаю position: fixed. Если вы посмотрите на ответ на верхний голос (на этот комментарий), вы увидите, что это, похоже, проблема Safari. Причиной position: fixed является нежелательным в этом случае, потому что данный код должен поддерживать несколько плавающих заголовков, которые расположены ниже друг друга и имеют "контейнерный" диапазон, где могут быть бесконечно вложенные контейнеры. Использование фиксированного позиционирования не только делает код более сложным в случае, когда эти плавающие заголовки живут в контейнере, который горизонтально прокручивается, но также делает компонент более хрупким в целом (вычисление смещений, когда виджет должен находиться в другом контейнере в другом месте страницы), Итак, семантически, позиционирование absolute соответствует моим потребностям лучше, чем fixed.

SECOND EDIT

Подумав о том, что Энтони рассказывал мне (чтобы я мог изобретать колесо), и, услышав о -wekbit-sticky от пользователя3716477, я хотел бы обновить вопрос, чтобы показать, что я пытаюсь сделать. Вы можете видеть, как работает мой код в каждом браузере, кроме Safari:

http://cl.ly/3y1i3C473G2G

Я узнал:

  • Вы не можете полагаться на scroll или действительно на любые подобные прокрутки события (например, mousewheel), так как они асинхронны по своей природе. Я отправил Apple ошибку, подробно изложив, что происходит, и по этой причине они закрыли ошибку.
  • В настоящее время нет реального способа делать то, что я хочу, - иметь несколько плавающих заголовков, которые складывают и заменяют друг друга. Думаю, мне придется ждать чего-то вроде -webkit-sticky, чтобы выйти.
  • Я должен включать всю соответствующую информацию в SO-вопросы отсюда. -Р

Спасибо, что сыграли парней! Вот точный ответ, который я получил от Apple:

Отношения с разработчиками Apple09-Jun-2014 13:16

Инжиниринг определил, что не планируется на основе следующего:

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

Теперь мы закрываем этот отчет об ошибке.

Если у вас есть вопросы относительно разрешения этой проблемы, пожалуйста, обновите свой отчет об ошибке с помощью этой информации.

Пожалуйста, регулярно проверяйте новые выпуски Apple для любых обновлений что может повлиять на эту проблему.

Ответы

Ответ 1

Поскольку между прокруткой с помощью трекпада и scroll существует , вы можете присоединить обработчик к дополнительному mousewheel событие, чтобы сгладить все.

$scrollContainer.on('scroll mousewheel', function () {
    // reinvent the wheel here
});

Вы можете увидеть в этой демонстрации здесь, что дрожание гораздо реже происходит при прокрутке с помощью трекпада. В демоверсии я вызывал обработчик при загрузке, чтобы устранить вспышку, когда вы впервые просматриваете Safari. Там может быть некоторый случайный джиттер, но если вы хотите свести к минимуму это, вы можете использовать ресурсоемкий способ с помощью setInterval и requestAnimationFrame.

Это может решить проблему на данный момент, но, как я уже говорил, этот подход эмуляции не идеален, и вы, скорее всего, столкнетесь с большими проблемами в будущем.

Ответ 2

Кажется, это ошибка с прокруткой Safari. Если вы перетащите полосу прокрутки вручную (не используйте джойстик трекпада для прокрутки), тогда нет дрожания.

Chrome (и другие браузеры) обрабатывают прокрутку по-разному, поэтому эта ошибка присутствует только в Safari. Вы можете отправить отчет об ошибке в Apple.

Ответ 3

Если вы используете что-то похожее на код jiddle, вам нужно проверить, является ли браузер сафари, а затем сделать его другим способом, например:

$(function () {
    var $header = $('h1'),
        $container = $('.container'),
        $scrollContainer = $('.scroll-container'),
        scrollContainerOffset = $scrollContainer.offset().top;
    $scrollContainer.on('scroll', function () {
        var top = Math.max(0, $container.offset().top * -1 + scrollContainerOffset);
        $header.css('top', top + 'px');

    });
});

Даже если это не так, как вы хотите, чтобы ваша проблема была решена, это может быть временным решением, которое может помочь...

Ответ 4

Как насчет небольшой реструктуризации, например: http://jsfiddle.net/me2loveit2/zT9KQ/6/

HTML:

<div>
<h1>Header</h1>
    <div class="container">
        <div class="content"></div>
    </div>
</div>

CSS

.container {
    height: 300px;
    position: relative;
    overflow-y:scroll;
}
.content {
    height:1000px;
}
h1 {
    position: relative;
    top:0px;
    left:0px;
    margin: 0;
    width: 100%;
    background: black;
    color: white;
}

Ответ 5

События прокрутки отправляются асинхронно в разных браузерах; вы не должны полагаться на них, чтобы делать такие вещи.

Лучшим решением будет использование позиции: -webkit-sticky; top: 0;

Ответ 6

Вы можете попробовать и отключить все и любую обработку прокрутки javascript-ish и просто удалить

position: relative; из .container.

После этого просто добавьте h1{ top:0; }, и он с радостью будет придерживаться .scroll-container.

Выдержка из абсолютного позиционирования CSS:

Расположите его в указанной позиции относительно своего ближайшего расположенного предка...

Чтобы объяснить - ваш абсолютный H1 будет искать дерево для первого элемента предка, который определяет свойство "position" и наследует его как опорную точку 0,0.

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

РЕДАКТИРОВАТЬ: В связи с оригинальным jsFiddle я сделал еще несколько удалений свойств:

http://jsfiddle.net/253Ss/

^ .container оболочка также может быть удалена, так как она не является более необходимой в техническом смысле.