Абсолютно позиционированные плавающие заголовки 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
оболочка также может быть удалена, так как она не является более необходимой в техническом смысле.