Легкий аккордеон используя CSS и jQuery

3 Август 2010

В этой статье я покажу как используя CSS и jQuery, можно сделать легкий и красивый аккордеон. Для его создания понадобиться написать лишь пару строчек кода на jQuery и немного на CSS, и для красоты будем использовать немного CSS3. И сразу хочу отметить, что в этой статье я рассказываю не как создать плагин для jQuery, а просто аккордеон, но если же тема будет востребовательна, тогда напишу статью как создать плагин :)

И так начнем с HTML каркаса, давайте создадим его. У нас будет общий контейнер, он будет самим аккордеоном, в нем будет последовательно идти, заголовок H3, блок, H3, блок и т.д. Где H3 это заголовок секции, а блок это её содержимое. Вот такой HTML у нас должен получится:

<div id="accordion">
	<h3 class="head">Секция #1</h3>
	<div class="block">Текст для секции #1</div>
	<h3 class="head">Секция #2</h3>
	<div class="block">Текст для секции #2</div>
	<h3 class="head">Секция #3</h3>
	<div class="block">Текст для секции #3</div>
</div>

Теперь когда у нас есть готовый каркас, нужно определить для него стили. Из разряда CSS3 для заголовка и для блока определим скругленные углы на 3 пикселя (свойство border-radius), для заголовка отдельно определим тень (свойство text-shadow).

#accordion h3.head {
	margin: 1px 0; padding: 5px 10px;
	font-size: 17px; font-family: Tahoma; font-weight: normal; color: #fff;
	background: #333;
	cursor: pointer;

	border-radius: 3px;
	-o-border-radius: 3px;
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;

	text-shadow: 1px 1px 0px #000;
	-o-text-shadow: 1px 1px 0px #000;
	-moz-text-shadow: 1px 1px 0px #000;
	-webkit-text-shadow: 1px 1px 0px #000;
}

#accordion div.block {
	padding: 10px; margin: 0;
	font-size: 13px; font-family: Tahoma; font-weight: normal; color: #888;
	background: #efefef;

	border: 1px solid #ccc;
	border-radius: 3px;
	-o-border-radius: 3px;
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
}

Также необходимо определить стиль для активной секции, например сделаем фон синего цвета. Добавим в конец CSS эти строчки:

#accordion h3.active {
	background: #369;
}

Ну вот вроде бы со стилями и все, теперь можно перейти ко вкусному, к jQuery :) И так не большой алгоритм: при загрузки страницы скрываем все секции кроме первой, делаем первую секцию активной, а также вешаем обработчик события на клик по секции. Вот собственно сам js-файл аккордеона:

// Когда страница полностью загружена
$(window).ready(function() {
	// Скрываем все секции кроме первой
	$('#accordion > div:not(:first)').hide();
	// Делаем первую секцию активной
	$('#accordion h3:first, #accordion div:first').addClass('active');
	// Если пользователь кликнул на секцию
	$('#accordion > h3').click(function() {
		// Сбрасываем все секции
		$('#accordion > h3').removeClass('active');
		$('#accordion > div').hide();

		// Делаем активной на которую кликнули
		$(this).addClass('active');
		$(this).next().addClass('active').show();
	});
});

Ну вот, теперь наш аккордеон полноценно работает. Но, все же чего-то в нем не хватает, давайте добавим анимации для наглядности.

// Когда страница полностью загружена
$(window).ready(function() {
	// запоминаем высоту и отступы каждого блока
	$('#accordion > div').each(function() {
		$(this).data('height', $(this).height());
		$(this).data('padding-top', $(this).css('padding-top'));
		$(this).data('padding-bottom', $(this).css('padding-bottom'));
	});

	// Скрываем все секции кроме первой
	$('#accordion > div:not(:first)').hide();
	// Делаем первую секцию активной
	$('#accordion h3:first, #accordion div:first').addClass('active');
	// Если пользователь кликнул на секцию
	$('#accordion > h3').click(function() {
		// Сбрасываем все секции
		$('#accordion > h3').removeClass('active');
		$('#accordion > div:visible').animate({
			height: 0,
			'padding-top': 0,
			'padding-bottom': 0
		}, 500, function() { $(this).hide() });

		// Делаем активной на которую кликнули
		$(this).addClass('active');
		box = $(this).next().addClass('active');
		$(box).animate({
			height: $(box).data('height'),
			'padding-top': $(box).data('padding-top'),
			'padding-bottom': $(box).data('padding-bottom')
		}, 500);
	});
});

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

Комментарии к записи

  • ДимКа
    4 Август 2010

    $(‘#accordion > div’).slideUp();
    Когда контента много слайдер прыгает..очень bad.

    • 5 Август 2010

      Поправил, теперь работает нормально. Пришлось прибегнуть к ручным средствам, так как slideUp и slideDown не всегда работают на ура.

    • ДимКа
      6 Август 2010

      $(this).data(‘padding-top’, $(this).css(‘padding-top’));
      $(this).data(‘padding-bottom’, $(this).css(‘padding-bottom’));
      Зачем запоминать значения паддингов, разве они не одинаковые для всех блоков?

    • 6 Август 2010

      Предполагается, что человек может для каждого блока задать разные паддинги :)

  • Владимир
    10 Август 2010

    Господа, а как сделать так чтобы все секции были закрыты? первая по умолчанию всегда открыта…

    • 10 Август 2010

      Убери из кода эти строчки:

      // Скрываем все секции кроме первой
      $(‘#accordion > div:not(:first)’).hide();
      // Делаем первую секцию активной
      $(‘#accordion h3:first, #accordion div:first’).addClass(‘active’);

  • Андрей
    31 Январь 2011

    ОГРОМНЕЙШЕЕ СПАСИБО ЗА СТАТЬЮ ! Я начал делать перввые успехи , и как оказалось , готовые ВИДЖЕТЫ только усуглубляют понимание и их настройку под себя . А вы показали простой сухой код .Еще раз СПАСИБО ОГРОМНОЕ ! Я люблю работать с TOGGLE переключалкой. Поэтомумне так ценна Ваша статья . $(#Andrew39).appendTo(.*)

  • 20 Февраль 2011

    у меня почемуто с другими jquery плагинами этот не хочет вместе работать .. все глючит!!! почему?? помогите..

    • 20 Февраль 2011

      Ошибки в JS есть какие нить? Я не могу помочь не видя, кинь ссылку, где ты его используешь.

  • winch
    5 Март 2011

    неплохо смотрится, но мне этого функционала оказалось мало.
    допустим у меня все секции помечены якорями:

    	<a rel="nofollow">Секция #1</a>
    	Текст для секции #1
    	<a rel="nofollow">Секция #2</a>
    	Текст для секции #2
    	<a rel="nofollow">Секция #3</a>
    	Текст для секции #3
    

    нужно сделать, что бы при загрузки странице по ссылке вида: accrdion.html#Section2 , активной активной оказывалась соответствующая секция.

    • 8 Март 2011

      Ну собственно на DOM Ready поставить событие, которое будет проверять хеш, и находить секцию с именем.

    • 31 Июль 2011

      Используй Печенье! :)

    • wonderer22
      1 Январь 2012

      winch, если решил проблему с открытией секции по ссылке с якорем, напиши плиз

    • 12 Январь 2012

      В общем. Каждой секции ставим имя, например так:

      <h3 class="head" id="acc-section1">Секция #1</h3>

      На DOM Ready вешает событие с таким кодом:

      var $section = $(location.hash);
      if ($section.length) {
      	$section.addClass('active').next().show().addClass('active');
      }

      Код на работоспособность не проверял, так что если что-то не так пишите.

  • 8 Апрель 2011

    Не работало (2ой пример), пока не добавил перед строкой 31
    $(box).show();
    У всех так или только у меня? В принципе логика понятна.
    А! и да, автору респект.

    • 8 Апрель 2011

      По сути должно работать! jQuery должен сам проставить display: block.

    • Михаил
      2 Май 2012

      Добрый день.
      Опишите пожалуйста более подробно про ***На DOM Ready вешает событие с таким кодом:*** — где это прописывать на странице, как точно писать и т.д. данная функция отслеживания ссылок является основной для навигации )))

    • 4 Май 2012

      Вот здесь (http://api.jquery.com/ready/) почитайте.

  • den
    15 Апрель 2011

    Доброго дня.Что нужно изменть,что бы сделать горизонтальный аккордеон?Спасибо.

  • 29 Апрель 2011

    Подскажите, пожалуйста, какие строчки нужно добавить, чтобы при нажатии на уже активную секцию она сворачивалась (становилась не активной). И что нужно сделать, чтобы вначале, «Когда страница полностью загружена», открытой была не первая секция, а уже активная на данный момент. Т.е. — вначале все секции закрыты, затем мы выбираем одну из секций, она становится активной, нужно, чтобы при обновлении страницы эта секция оставалась активной.

  • Gronris
    9 Май 2011

    Такая ошибка:
    $(this).data is not a function

    $(this).data(‘height’, $(this).height());

    (firebug)

    • 25 Май 2011

      Хммм, проверил в FF 3.5, 3.6, и 4й версии, проблем не обнаружил :)

  • Вера
    19 Август 2011

    Спасибо. Вы бы знали, сколько я искала. Много материала, но нет понятного. Вот, например — карусель от Финна Рудольфа так мне и не далась — нет знаний. Вы первый, чья работа помогла мне, как новичку. Сегодня вы сделали меня счастливой, я закрыла десятидневный этап работы.

    • 20 Август 2011

      Всегда пожалуйста :)

  • Delirium
    20 Сентябрь 2011

    Спасибо за статью. Очень полезно для новичков вроде меня. Скажите, а можно сделать так, чтобы по какой-нибудь кнопке (типа «Показать все») разворачивались одновременно все блоки и находились в открытом состоянии пока не нажмешь еще раз на эту же кнопку (или на другую кнопку (типа «Скрыть все»)). Очень жду ответ.

    • 20 Сентябрь 2011

      Да можно, надо выполнить следующий код по нажатию на кнопку «показать все»:

      $('#accordion > h3, #accordion > div').addClass('active');

      Для того чтобы скрыть все, следующий код:

      $('#accordion > h3, #accordion > div').removeClass('active');
    • Delirium
      20 Сентябрь 2011

      Спасибо)

    • 20 Сентябрь 2011

      Всегда рад помочь :)

  • Павел tp-20
    17 Октябрь 2011

    а про сторонный скриптик-то промолчали)) хотя в исходнике он есть. http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js — этот. А как раз таки без него ничего и не работает!!!

    • 17 Октябрь 2011

      Это сам jQuery вообще-то!

    • Павел tp-20
      17 Октябрь 2011

      как так?
      в исходнике у вас есть accordeon.js а в index.html прописан ещё и jquery.min.js
      так вот если последний отключить (jquery.min.js ) то работать скрипт не будет)))

    • 18 Октябрь 2011

      Правильно. Потому что jquery.min.js это и есть сам jQuery. Вы вообще понимаете, что такое jQuery, или хотя бы заголовок статьи читали? :)

    • Павел tp-20
      18 Октябрь 2011

      да, я понимаю что такое jQuery. но тогда встаёт вопрос — зачем в index.html подключать два ОДИНАКОВЫХ скрипта, один из которых в вашем исходнике — accordion.js, а другой jquery.min.js. Вы говорите что это и есть сам скрипт. зачем они тогда там вдвоём? понимаете о чём я? (извините если нафлудил в вашей теме)))

    • 18 Октябрь 2011

      С чего вы взяли, что они одинаковые? Файл accordion.js отвечает за работу аккордеона, а файл jquery.min.js сама jQuery библиотека!

  • Павел tp-20
    18 Октябрь 2011

    теперь понятно))) sorry если что) учусь)

  • Дмитрий
    26 Октябрь 2011

    Скажите пожалуйста, как сделать чтобы когда щелкаешь на открытую секцию, то она закрывалась?

    • 26 Октябрь 2011

      После строк:

      // Делаем активной на которую кликнули
      $(this).addClass('active');

      впиши следующее:

      if ($(this).next().hasClass('active')) {
          $(this).next().removeClass('active').animate({
              height: 0,
              'padding-top': 0,
              'padding-bottom': 0
          }, 500, function() {
              $(this).hide()
          });
          return;
      }

      Работоспособность не проверял, так что если будут ошибки пишите, тогда уже проверю :)

    • Дмитрий
      26 Октябрь 2011

      Спасибо!
      Вроде работает, только блоки теперь резко прыгают при закрывании и открывании(это не суть важно). Иногда происходит косяк при открывании другой секции, текущая закрывается, а новая не открывается. Но вот только не всегда.

    • Дмитрий
      26 Октябрь 2011

      Убрал анимацию и все клева заработало! Спасибо!
      .animate({
      height: 0,
      ‘padding-top’: 0,
      ‘padding-bottom’: 0
      }, 500, function() {
      $(this).hide()
      });
      заменил на .show();

    • 26 Октябрь 2011

      Ну вот и славненько :)

    • Дмитрий
      26 Октябрь 2011

      Всеравно через раз работает

    • 26 Октябрь 2011

      Конкретней?

  • Дмитрий
    26 Октябрь 2011

    Ситуация такая: у меня две секции. Открываю первую секцию все нормально -> вторую — нормально все -> опять первую ( контент дива block остаеться, а сам див как будто сварачивается и вторая секция под контентом) -> нажимаю среди текста на вторую секцию(такая же фигня, но так как секций больше нет, под текстом прозрачно). Уф вроде объяснил… :))

    • 26 Октябрь 2011

      Есть ссылка на пример?

    • Дмитрий
      26 Октябрь 2011

      неа, на локалке делаю, код могу кинуть

    • 26 Октябрь 2011

      Кинь код на мыло, оно есть на странице «Обо мне».

    • 26 Октябрь 2011

      Выслал нужный вам код на ваше мыло!

  • yura
    16 Ноябрь 2011

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

    у меня такая же примерно ситуация, как здесь >>>>>
    Ситуация такая: у меня две секции. Открываю первую секцию все нормально -> вторую – нормально все -> опять первую ( контент дива block остаеться, а сам див как будто сварачивается и вторая секция под контентом) -> нажимаю среди текста на вторую секцию(такая же фигня, но так как секций больше нет, под текстом прозрачно). Уф вроде объяснил… :))

    заранее спасибо

    • 16 Ноябрь 2011

      Простите, но я ничего не понял. Видео в студию :)

  • Genius
    29 Декабрь 2011
    <h3 style="display:none;" class="head"></h3>
    <div style="display:none;" class="block"></div>
  • Никита
    9 Апрель 2012

    Привет ребят! У меня возникла подробность в заголовках Секция #1 добавить стили при помощи div’ов например, мне нужно чтобы было к примеру:
    Секция #1 — т.е вместо h3, div’ка. Я делаю:

    #accordion #is.head
    {
    	margin: 1px 0; padding: 5px 10px;
    	font-size: 17px; font-family: Tahoma; font-weight: normal; color: #fff;
    	background: #333;
    	cursor: pointer;
    
    	border-radius: 3px;
    	-o-border-radius: 3px;
    	-moz-border-radius: 3px;
    	-webkit-border-radius: 3px;
    
    	text-shadow: 1px 1px 0px #000;
    	-o-text-shadow: 1px 1px 0px #000;
    	-moz-text-shadow: 1px 1px 0px #000;
    	-webkit-text-shadow: 1px 1px 0px #000;
    }
    
    #accordion #is.active
    {
    	background: #369;
    	margin: 1px 0; padding: 5px 10px;
    	font-size: 17px; font-family: Tahoma; font-weight: normal; color: #fff;
    
    	cursor: pointer;
    
    	border-radius: 3px;
    	-o-border-radius: 3px;
    	-moz-border-radius: 3px;
    	-webkit-border-radius: 3px;
    
    	text-shadow: 1px 1px 0px #000;
    	-o-text-shadow: 1px 1px 0px #000;
    	-moz-text-shadow: 1px 1px 0px #000;
    	-webkit-text-shadow: 1px 1px 0px #000;
    }
    
    #accordion div.block
    {
    	padding: 10px; margin: 0;
    	font-size: 13px; font-family: Tahoma; font-weight: normal; color: #888;
    
    	border: 1px solid #ccc;
    	border-radius: 3px;
    	-o-border-radius: 3px;
    	-moz-border-radius: 3px;
    	-webkit-border-radius: 3px;
    }
    $(window).ready(function()
    {
    	// запоминаем высоту и отступы каждого блока
    	$('#accordion &gt; div').each(function()
    	{
    		$(this).data('height', $(this).height());
    		$(this).data('padding-top', $(this).css('padding-top'));
    		$(this).data('padding-bottom', $(this).css('padding-bottom'));
    	});
    
    	// Скрываем все секции кроме первой
    	$('#accordion &gt; div:not(:first)').hide();
    	// Делаем первую секцию активной
    	$('#accordion #is:first, #accordion div:first').addClass('active');
    	// Если пользователь кликнул на секцию
    	$('#accordion &gt; #is').click(function()
    	{
    		// Сбрасываем все секции
    		$('#accordion &gt; #is').removeClass('active');
    		$('#accordion &gt; div:visible').animate({height: 0, 'padding-top': 0, 'padding-bottom': 0}, 500, function() { $(this).hide() });
    
    		// Делаем активной на которую кликнули
    		$(this).addClass('active');
    		box = $(this).next().addClass('active');
    		$(box).animate(
    		{
    			height: $(box).data('height'),
    			'padding-top': $(box).data('padding-top'),
    			'padding-bottom': $(box).data('padding-bottom')
    		}, 500);
    	});
    });

    Но при нажатии на первый заголовок, div — он исчезает, но конент появляется. Что я делаю не правильно?

    • 10 Апрель 2012

      Ссылку на пример, а то в данный момент нет возможности воспроизвести!

  • Sergey
    17 Апрель 2012

    А у всех в IE9 коряво работает? На опере гуд все

    • 17 Апрель 2012

      Коряво это как именно, в данный момент нету возможности проверить.

  • Кирилл
    10 Май 2012

    А как учесть в этом параметре:
    height: $(box).data(‘height’)
    высоту всех изображений, которые находятся в этом блоке?
    Проблема в том, что высота считается по тексту без учета изображений и после раскрытия блок получается меньшей высоты, чем должен быть.

    • Кирилл
      10 Май 2012

      Анимацию убрал, все само собой исправилось.

Оставьте свой комментарий