Простой аккордеон
30 Mar, 2009Это те самые, странно разворачивающиеся и очень редко нужные менюшки. ;)
Так как jquery стал почти стандартом в индустрии, дальше я буду говорить только о нем.
Проблема
На сайте понадобился такой элемент. Выглядят они обычно как-то так. Я буду считать что один из его блоков должен быть всегда открыт, но на деле, это не очень важно. Ну и предполагаем, что по невероятному совпадению на сайте уже есть jquery. Потому что подключать его только ради меню глупо, согласитесь. Но, если очень хочется, то, как всегда, можно. HTML — обычныйdl
, в котором dt
будут кликаться, а dd
раскрываться, вот такой:
- <dl>
- <dt class="b-acc">Заголовок</dt>
- <dd>
- Контент
- </dd>
- ...
#1: Своими силами
Сделать такой эффект своими силами вроде бы совсем несложно. Всего-то нужно схлопывать-расхлопывать два блока одновременно.- $(".b-acc").click(function(){
- if($(this).hasClass('b-acc-active')) {
- // сделать что-то если блок уже открыт
- }
- else{
- $("dd:visible").slideUp();// закрыть «видимый» блок
- $(this).next().slideDown();// открыть новый блок
- // и переключить класс b-acc-active
- ...
- }
- return;
- });
#2: Плагин
Это будет первое что вы нагуглите. Проще всего его подключить и вызвать. И если всем плевать на размер файла, а также на то, что вы подключили кучу мусора (разве что ваш сайт будет увешан всеми видами аккордеонов). На этом можно и закончить уже разработку.Я сделал простой пример работы плагина. Нижняя кромка больше не прыгает.
Однако добавилось 8 Кбайтов плагина.
#3: Улучшенный вариант
Но так хотелось все оставить простым, так не хотелось подключать кучу лишнего кода, который, я знал, никому на сайте уже не понадобится. И я решил раскопать проблему, почему же нижняя граница дергается, и как это все исправить. В конце концов оказалось, что функции slideUp и slideDown меняют высоту блоков не по целым значениям. То есть, в процессе анимации высоте блока присваиваются значения вроде 2.157305232px. При этом, округление в браузерах работает очень по-разному, что и приводило к «вибрации» нижней кромки аккордеона.Наконец забравшись в недра плагина, я нашел решение, которое также познакомило меня с малоизвестными возможностями jquery.
Идея примерно такая: мы начинаем «схлопывать» видимый блок, при этом, на каждом шаге анимации, рассчитывать высоту расхлопываемого блока так, чтобы сумма их оставалась константой. То есть, если на каком-то шаге высота закрываемого 50 пикселей, то высота открываемого будет 100 (в сумме 150px).
Для этого в jquery есть специальный механизм. В функции animate, есть возможность исполнять что-то на каждом шаге анимации. Называется этот коллбэк — step.
Финальное работающее решение выглядит примерно так:
- toShow = $(this).next();
- toHide = $(".accordion dd:visible");
- staticheight = toHide.height(); //определить высоту блоков, 150px
- toShow.css({ height: 0,display: 'block' }); // открываемый делаем "видимым" с высотой 0, теперь он готов к анимации
- toHide.animate({height:"hide"},{ // начинаем скрывать видимый
- step: function(now) { // на каждом шаге выполняем, now - значение height в каждый момент
- var current = staticheight - now; // собственно рассчет
- if ($.browser.msie || $.browser.opera || $.browser.safari) { // все округляют по-своему
- current = Math.ceil(current);
- }
- toShow.height(current); // присваиваем высоту
- },
- duration: 500
- });
Понятно что конкретно этот аккордеон не универсален, но зная как работает step можно легко применить его к любому другому способу.
В конце
Все это далеко не rocket science, но мои долгие попытки найти легкое решение этой проблемы приводили только к плагину. Который я, ну никак не хотел подключать. Потому надеюсь кому-то это сэкономит усилия и код. И буду рад услышать ваше мнение об этом.Разумеется, только ради аккордеона не стоит подключать jquery, но, обычно, сайты с такими навороченными меню содержат еще кучу всяких анимаций и действий. И потому, в результате, все равно удобнее использовать фреймворк для разработки.
step
, про который нигде так и не нашел документации (но где-то по слухам есть) @Mourner - дадада, когда сделал фон для разворачиваемых пунктов, мой фф/mac тоже стал глючно прорисовывать :) Но я решил оставить, всегда забавно видеть столь редкие баги в ФФ =)