Pull to refresh

Comments 41

Круто. Плюс за такие археологические раскопки, однозначно.
Хотя, лично я отслеживаю состояние всех скрывающихся элементов глобальными переменными, т.е. на любую динамически скрывающуюся штуку у меня всегда есть глобальная булевая переменная _show_status, которая имеет значение по умолчанию и меняется при изменении состояния элемента. Имхо, гораздо удобнее.
Имел ввиду [elementName]_show_status.
А если необходимо узнать виден ли вложеный элемент? Такое бывает в сложных приложениях (н-р контрол в соседнем табе). И если есть десятка два контролов, это становится очень неудобно.
То, что я предложил в конце - это самое простое и правильное решение:
если мы договоримся, что скрытые элементы должны иметь класс hide, то все сведется к определению наличия этого класса у элемента или его родителей.
добавил еще одну страницу в статью с описанием этого решения.
Замечательный текст!
Спасибо большое - очень полезно!
Хотелось бы добавить вот что: есть методика скрывания ненужных в данный момент абсолютно спозиционированных элементов свойствами "top: -9999px" / "left: -9999px" вместо "display: none" (такая практика бывает иногда необходимой, чтобы привести в чувство IE).

Как нетрудно догадаться, запрос offsetHeight скрытых таким образом элементов не даст нам ничего хорошего.
да, но это отлично подойдет для решения с классом hide
причем для ie можно сделать одну реализацию а для остальных другую
а пример необходимости top: -9999px можно? я как-то никогда с таким не сталкивался. С visibility косяки у IE знаю, а с display не встречал
Пепелсбей сейчас у себя на сайте перелопатил, поэтому ссылка из веб архива:
http://web.archive.org/web/20061201201724/pepelsbey.net/pro/ddm/
за сам пример спасибо. Но если заменить top: -9999px на display:none, то все по прежнему работает. Какой смысл тогда использовать top: -9999px ?
За сам пример - спасибо. Но если заменить top: -9999px на display:none то все по-прежнему работает. Какой тогда смысл использовать top: -9999px ?
Большое спасибо, особенно за ссылки. Теперь понятно, почему у меня jquery-код в некоторых случаях так необычайно тормозит.
хм, мне очень любопытно чем руководствовался человек поставивший минус комментарию. в статье ведь объясняется теория, объясняющая замедление. и это имеет отношние к любой библиотеке.
var view=document.defaultView;

if(view && document.defaultView)

В чём смысл этого кода?
спасибо, опечатка.
function fnOffset(el)
{
return !!el.offsetHeight;
}

function fnStyle(el)
{
return el.style.display=='none';
}

Где c – тестовый контейнер.


Может быть, всё-таки, тестовый контейнер «el»?..
да, спасибо, опечатка
Кстати, недавно обсуждаемый пример с техногрета, про PNG-рамку, мне как-то тоже "красивым" не показался.
спасибо за статью. В полку оптимизаторов прибыло? :)
Пожалуйста. :)
Если честно, прочитав заметку Владимира Токмакова, я сразу же подумал, что предлагаемый им подход не оптимален из-за reflow. Но это наложилось на очередное заявление одного знакомого, который ссылается на Кодоводство, как на библию, и на Лебедева, как пророка ее. Вот я и решил аргументировано объяснить, что прислушиваться к советам великих нужно, но также нужно понимать разницу между безоговорочным доверием и осознанным согласием. Это было поводом. А что получилось в результате – Вы видите. ;) Отсюда такой странный заголовок. Всю остальную мораль я убрал, чтобы не портить статью, а заголовок забыл.

На счет "оптимизаторства". Я учился программировать с ассемблера. Добивался, чтоб программки не тормозили на двойке с двумя метрами памяти и влезали в загрузочный сектор дискетки. Это наложило свой отпечаток на мое профессиональное развитие. Потом я изучил Си, затем Си++, но понимание того, как все устроено у компилятора внутри, было всегда. Затем я не мог принять интерпретируемые языки из-за того, что практически ни на что нельзя повлиять. Однако постепенно осознал, что скорость кода, в какой-то мере, допустимо приносить в жертву скорости разработки. Однако неоптимальный код я не могу писать до сих пор. Наверное, это стало чертой профессионального характера. А накопив багаж знаний по какому-либо языку или технологии, рефракторинг с целью оптимизации приходится проводить все реже.
и влезали в загрузочный сектор дискетки

ай-яй... собственный One-Half?!
да нет, просто прожки работающие без доса, юзая тока функции биоса. на сколько помню написал простейший файловый менеджер и текстовый редактор. потом забил...
да нет, просто прожки работающие без доса, юзая тока функции биоса.

а... :")
ну тады респектище!
круто написано.
спасибо за статью!
UFO just landed and posted this here
Здравствуйте, автор статьи!
Ответьте, пожалуйста, на следующий вопрос (если ответ не является секретом). На основании чего Вы сделали вывод о том, что запрашивая offsetHeight, мы "измеряем" элемент, что вынуждает браузер сделать reflow? Мне понятно то, что таким образом мы "измеряем" элемент, но почему этот процесс становится причиной повторного вывода (laying out) элемента?
почему этот процесс становится причиной повторного вывода (laying out) элемента?

Это не так. Этот процесс коммитит отложеные reflow. Если их небыло, то reflow не происходит - смотрите самый первый тест.

Что же произойдет в случае если они были.
Представьте, что в DOM есть таблица с двумя ячейками. Ширина таблицы - 100px, ширина ячейки - 50%.

examples

Мы меняем содержимое первой ячейки и хотим узнать какова ее ширина. Казалось бы - 50px. Сравним таблицы 1 и 2.
Как браузер должен отличить первый случай от второго? Для этого требуется сделать layout не только для самого элемента, но и для его детей. Теперь рассмотрим третий случай. Как мы видим от содержимого могут измениться параметры родительского элемента, что потребует его пересчета. Примеры 4 и 5.
Таким образом от изменившегося элемента распространяется лавина reflow.

Efficient JavaScript:
As stated earlier, the browser may cache several changes for you, and reflow only once when those changes have all been made. However, note that taking measurements of the element will force it to reflow, so that the measurements will be correct. The changes may or may not not be visibly repainted, but the reflow itself still has to happen behind the scenes.

This effect is created when measurements are taken using properties like offsetWidth, or using methods like getComputedStyle. Even if the numbers are not used, simply using either of these while the browser is still caching changes, will be enough to trigger the hidden reflow.
Я извиняюсь за то, что невнятно высказался. Лучше я приведу пример. В вашем тесте в функцию test_offset добавьте вот это:

var o = document.getElementsByTagName('meta').item(0);

И пусть в цикле в вызове функции fnOffset будет именно этот аргумент (переменная "o" вместо переменной "с").
Вы это имели ввиду:
function test_offset()
{
    var c=init();
    var o = document.getElementsByTagName('meta').item(0);
    profile('offsetHeight');
        for(var i=0; i<1000; i++){
            fnOffset(o);
            c.appendChild(t.cloneNode(true));
        }
    profileEnd();
    clean(c);
}

У меня цифры остаются прежними во всех браузерах.

Коммитятся все отложенные reflow, а не только те, которые связаны с каким-то элементом. Понятно почему? Если нет постараюсь объяснить еще раз.
>Коммитятся все отложенные reflow, а не только те...

Вы ведь только теперь написали: "не только те" (об этом и речь).

>Понятно почему? Если нет...

А вот так не надо.

>Мы получили универсальное решение...

Проверьте свое "универсальное решение" на этом примере:

<div class='hide'>
<span id='test'>test</span>
</div>

<script type='text/javascript'>

alert(isHiddenFast(document.getElementById('test')));

</script>

>>Коммитятся все отложенные reflow, а не только те...
Я думаю эта фраза некорректна. Я так написал чтоб было понятнее. reflow не связан с каким либо элементом, у reflow есть только точка старта, от которой распространяются изменения. И будет ли затронут тот или иной элемент зарание не известно.

>Вы ведь только теперь написали: "не только те" (об этом и речь).
Теперь понял, что Вы имели ввиду. Четкого определения reflow я не нашел ни на русском ни на английском. Если можете поправить определение reflow чтобы это было понятно - внесите свой вклад :)

>>Понятно почему? Если нет...
>А вот так не надо.
да ладно Вам, я ж по-доброму ;)

>>Мы получили универсальное решение...
>Проверьте свое "универсальное решение" на этом примере:
О! спасибо Вам большое за обнаружение этой ошибки.
В цитируемой статье явно указано, что вызов getComputedStyle также вызывает reflow, и причины отсутствия этого в IE и FF непонятны, хотя и радуют.

Теперь понятны "причины отсутствия" - по тому что не работает :)) Странно, что я не заподозрил подставу сразу.

Т.о. "универсальным решением" будет функция isHidden. ;)
>И будет ли затронут тот или иной элемент зарание не известно.

Почему же не известно? Если верить статьям, то:
Incremental reflow подразумевает отложенное выполнение, т.е. объединение всех заданий по вычислениям для последующей обработки (нечто, напоминающее пакетный режим). Однако любые дополнительные запросы к системе за вычислениями вызывают Reflow method корневой структуры-html, от которой начинается рекурсивное движение к целевой структуре по дереву документа и выполнение вычислений на каждом этапе. И тут, по причине асинхронной природы этого процесса, начинается еще и одновременное выполнение всех тех задач, которые были ранее поставлены в очередь.

>Если можете поправить определение reflow чтобы это было понятно - внесите свой вклад :)

Если бы мог, то уже бы внес. ;)
Хотя, как говорится, попытка не пытка, и если в качестве базиса выбрать статью Notes on HTML Reflow, то можно попытаться определиться следующим образом.
Reflow - это вычисление параметров геометрии форматируемых структур. В HTML такая структура, как правило, соответствует одному элементу, и она (эта структура) имеет форму прямоугольника (при вычислениях используются его высота, ширина и отступ от родительской структуры).

>Нужно подобрать лучший параметр ветвления вместо window.GeckoActiveXObject.

Было бы разумно проверять в условии наличие тех свойств и методов, которые необходимо использовать:
if (document.defaultView && …

>Т.о. "универсальным решением" будет функция isHidden. ;)

Обе isHidden жестко привязаны к имени класса, и, следовательно, не могут называться универсальными. К тому же та, что внутри isHiddenFast будет работать некорректно (проблема: return !!p && p!=b; => нет проверки класса элемента, если элемент - это body). Чтобы увидеть это, измените ранее упомянутый пример на:

<body class='hide'>
<span id='test'>test</span>
</body>
> Было бы разумно проверять в условии наличие тех свойств и методов, которые необходимо использовать:
> if (document.defaultView && …
там дело немного в другом document.defaultView есть и в Safari, но в Safari быстрее работает isHidden

>>Т.о. "универсальным решением" будет функция isHidden. ;)
> Обе isHidden жестко привязаны к имени класса, и, следовательно, не
> могут называться универсальными.
если они не привязаны к классу, то это должны быть не isHidden, а doParentshaveTheFollowingClassName ;) но если это принципиально, то исправить, чтобы имя класса передавалось параметром - не проблема.

> К тому же та, что внутри
> isHiddenFast будет работать некорректно (проблема: return !!p &&
> p!=b; => нет проверки класса элемента, если элемент - это body).
а какой смысл скрывать body? это сделано нарочно.

Таки собрался дать более четкое определение reflow. Думаю теперь все четко написано.

PS. спасибо большое за комментарии!
>спасибо большое за комментарии!

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

>а какой смысл скрывать body?

Дело в том, что все может быть несколько сложнее (именно поэтому я считаю, что написать что-то универсальное - это "не поле перйти"). Приведу пример, не вдаваясь в подробности. Вот упрощенное правило стиля тела документа – поразмышляйте (когда будет время) о том, для чего это может понадобится и как это может изменить скрипты:

body.hide .hide {
display:none;
}
>поразмышляйте (когда будет время) о том, для чего это может понадобится и как это может изменить скрипты:

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

однако в данном случае body.hide определяет общее состояние, а сам .hide - состояние конкретного виджета. а нам надо найти именно состояние виджета. и как состояние приложения называтся не суть важно. тем более, что в таком случае мы получим не то что хотели:

<body class="hide">
<widget class="hide"></widget>
<p id="p1">test</p>
</body>
isHidden($('p1')); // ==true

поэтому состояние приложения лучше назвать по другому.

или я что-то упускаю?
>однако в данном случае

Если рассматривается частный случай, но термин "универсальное решение" неуместен. Разве нет?

>или я что-то упускаю?

Упускаете то, на что я намекал раньше (чуток перефразируя): isHidden не могут называться универсальными. Можно даже добавить, что вообще не может быть совершенного решения. Это я и пытался показать (но не доказать) на своих примерах. .
хм. понял что вы имеете ввиду.

Можно изменить функцию на:
function doesElementInheritCSSClass(el, cls)
{
    var p=el;
    var re=new RegExp('(^|\\s)'+cls+'($|\\s)');
    while(p && !re.test(p.className))
        p=p.parentNode;
    return !!p;
}
>Можно изменить функцию на...

Конечно можно. Я просто пытаюсь отметить, что случай необычный, из разряда тех, для которых нужны также необычные методы. Я считаю, что есть простые и стандартные алгоритмы, которые можно расписать раз и навсегда, вроде addClassName, removeClassName, setOpacity и т.д. А вот в данном случае написать универсальное решение не то, чтобы не возможно, а скорее не нужно. Будет легче отталкиваться от конкретной ситуации (Вы ведь оптимизатор – понимаете). Можно, конечно, пытаться, но при этом будем наступать на одни и те же грабли. Взять, хотя бы, решение Владимира Токмакова. Автор руководствовался желанием найти унифицированное решение. И чем это все закончилось? Вашей статьей... ;)
Перезалейте пжл изображения на хабрасторэджь, не отображаются.
Sign up to leave a comment.

Articles

Change theme settings