Универсальный jQuery-скрипт для блоков с вкладками (табами)

Универсальный jQuery-скрипт для блоков с вкладками (табами)

Содержание: Вступление Код jQuery-скрипта для переключаемых блоков с вкладками Добавлено 07.03.2010 (обновлено 09.04.2015) Скачать HTML-код, который нужно использовать для скрипта Обязательные CSS-стили для вышеуказанного HTML-кода Примеры к содержанию ↑Вступление Мое знакомство с фреймворком jQuery произошло в 2008-м году, после того, как, однажды, на ...

Полезные комментарии (8)
Комментарии (950)
  1. 1

    Огромное спасибо Дмитрий, пригодилось. Сделал RT.

  2. 3
    Guga

    спасибо за скрипт, перепробовал несколько вариантов на Maxsite и все криво работали…
    этот же заработал сразу, так что дальше изобретайте такие хорошие «колеса» ;)

  3. 5
    Sun

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

  4. 6

    вариант с jQuery UI не уложится в 4кб :)

  5. 9
    hardmid

    К сожалению, в Вашем примере если отключить JavaScript, то текста не будет. Для робото-поисковых систем это не есть гуд.
    Пробовали для этого случая включить контейнеры ?

  6. 12

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

  7. 13
    artanik

    Спасибо за пост, это как-раз то что я искал, с jQuery работаю не давно. Всё чётко и ничего лишнего.
    P.S.
    И ещё спасибо отдельное за предыдущие посты, всё-таки я чего-то научился ;)

  8. 14

    Не знаю, надо ли тебе это слышать в очередной раз, но — ты молодец, Дима!

  9. 16

    Ачуметь! Плагин бомба. Дима, большой РЕСПЕКТ и УВАЖУХА!

  10. 18

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

    [b]P.S.[/b]
    А вообще в последнее время всё реже встречаются вот такие вот люди как Дмитрий, которые делятся своими наработками с массами, пусть даже ктото скажет: я это придумал уже давно, и пользуюсь. Но ведь этот ктото не пожелел поделиться с людьми….. а Дмитрий хотябы нашол время, чтобы расписать, разложить по полочкам для начинающих и не очень вебмастеров нужную информацию.

    [b]P.P.S.[/b]

    Ну и пусть, пусть я “изобрел колесо”, главное, что я получаю большое удовольствие от данного процесса

    солидарен с мнением автора.

    • 19

      На здоровье. Спасибо за комментарий!

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

      Я для того и веду блог, чтобы делиться интересной и нужной информацией =)

  11. 20
    Александр

    Здорово!
    Однако, при включении вертикально-расположенных табов, страница неприятно перескакивает вверх. Говорю про онлайн пример.
    Браузер — Опера 10.

    • 21

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

      К сожалению, я не знаю, каким образом устранить эту неприятность.

      • 22

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

      • 23
        ITech

        Подскажите, кто-то уже нашел решение этой проблемы?

          • 25
            ITech

            Ура! Решил у себя проблему с перепрыгиванием в начало страницы при переключении табов! Вот живой пример: http://injoit.com/what-we-do/

            Реализовал твой код, Dimox, на своем сайте с небольшими изменениями. Вся загвоздка в том, что все div.box необходимо обтянуть еще одним div и для него определить фиксированную высоту!

            Так как у меня контент в табах на сайте постоянно меняется, подключил механизм Math.max.apply для расчета максимально возможной высоты вложенного дива .box. Эту высоту и задавал внешнему диву..

            Для эффекта появления использовал вместо show() animate() с указанием четких параметров:

            (function($) {
            $(function() {
            
            	$('ul.tabs').delegate('li:not(.current)', 'click', function() {
            		$(this).addClass('current').siblings().removeClass('current')
            		.parents('div.section').find('div.box').hide().eq($(this).index()).animate({height: 'auto', width: 'auto', opacity: 'show'}, 'slow');
            	})
            
            /*--Определение максимальной высоты для блока-контейнера .box-wrap--*/
            	Array.max = function(array) {
             return Math.max.apply(Math,array);
             };
            	var heights = $('.box-wrap div.box').map(function() {
             return $(this).innerHeight();
             }).get();
            	$(".box-wrap").height(Array.max(heights));
            /*--------*/
            
            })
            })(jQuery)
            

            И собственно HTML:

            <div class="section vertical">
            <ul class="tabs">
            	<li class="current"><span>Mobile</span></li>
            	<li><span>Social and Web</span></li>
            	<li><span>Cloud</span></li>
            </ul>
            <div class="box-wrap">
            <div class="box visible">
            ---
            </div>
            <div class="box">
            ---
            </div>
            <div class="box">
            ---
            </div>
            </div>
            </div>
            

            Не знаю, правильно я сделал или нет, но главное ведь, что оно работает) Буду рад услышать твои комментарии по данному поводу.

  12. 31

    Очень элегантное решение.
    Вопрос: нужно ли для каждого блока табов вставлять отдельную такую функцию или этот скрипт обрабатывает все блоки с табами на странице?

  13. 33
    anStream

    Я бы рекомендовал добавить ещё пару-тройку строк кода, чтобы реализовать данное решение в виде метода (плагина) jQuery, для использования в (возможно) позже появившихся (например с ajax-запроса) таб-блоках, на которые существующий код, естественно, не подействует, так как выполняется единожды.
    e.g. $(‘#foo’).myTabs();

    P.S. Решение хорошее и лёгенькое. Сам однажды такое создал, но с дополнительными хендлерами, запретом нажатия табов, запретом «покидания» таба при определённых условиях и т.п. Но это только потому, что была в этом потребность.

  14. 34
    Ramazan

    Спасибо.Полезно. Возьму на заметку!

  15. 35
    gordi

    Для полной универсальности, может быть стоит совместить вертикальные и горизонтальные закладки в единое целое.
    Тогда к примеру выбрав в вертикальном табе одну из закладок,
    на ней используем горизонтальные, что несколько расширяет область применения.

    Возможно, есть смысл сделать закрытие вкладки по клику на открытой, тоже весьма полезная фишка.

    • 36

      Для полной универсальности, может быть стоит совместить вертикальные и горизонтальные закладки в единое целое.
      Тогда к примеру выбрав в вертикальном табе одну из закладок,
      на ней используем горизонтальные, что несколько расширяет область применения.

      Совсем ничего не понял.

      Возможно, есть смысл сделать закрытие вкладки по клику на открытой, тоже весьма полезная фишка.

      Что значит «закрытие»?

      • 37
        gordi

        Совсем ничего не понял.

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

        Что значит “закрытие”?

        Клик на ссылке открытого таба превращает все в горизонтальное или вертикальное меню.
        Может быть даже при открытии страницы все табы свернуты.

        • 38

          Приблизительно так

          Запихни div.section в div.box другого div.section и получишь то, что надо.

          Клик на ссылке открытого таба превращает все в горизонтальное или вертикальное меню.

          Непонятно, что это и для чего нужно.

          Может быть даже при открытии страницы все табы свернуты.

          Просто удали класс .visible из хтмл-кода и все будут свернуты.

  16. 39
    МОТОРИСТ

    Добавьте жирный заголовок в текст во вкладке и посмотрите как он будет выглядеть в ИЕ 6,7 при клике на этой вкладке.
    (Шрифт получается «обглоданным»).

  17. 40
    MOTORIST

    Сравните шрифт в горизонт. вкладке (при клике на нее) и внизу (вертикальных вкладках).(в ИЕ 6,7)
    Если решите проблему, то табы будут отличные. Я пока не нашел решения(((.

  18. 44

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

  19. 45

    (в ИЕ 6,7)

    Есть более простое решение — не использовать гов**браузеры, и прикрутить к сайту скрипт, запрещающий просмотр сайта через IE 6. сколько можно пользоваться браузером, который устарел много лет назад, почему никто не пишет, типа «сайт криво отображается в Opera 7 или FF1 ??

  20. 47
    spiller

    Спс за скрипт. Давно такой искал. Жду новых разработок ))

  1. 1

    Видимо, это косяк Файерфокса. А по поводу Вконтакте вот тут описывал решение.

  2. 2
    evgen

    путем нехитрых манипуляций делаем Ваш скрипт еще более универсальным

    (function($) {
    	$(function() {
    
    		$('ul.tabs').delegate('li:not(.current)', 'click', function() {
    			$(this).addClass('current').siblings().removeClass('current')
    				.parents('div.section').eq(0).find('>div.box').hide().eq($(this).index()).show();
    			return false;
    		})
    
    	})
    })(jQuery)
    
    <div class="section">
    
    	<ul class="tabs">
    		<li class="current">Первая вкладка</li>
    		<li>Вторая вкладка</li>
    		<li>Третья вкладка</li>
    		<li>Червертая вкладка</li>
    	</ul>
    
    	<div class="box visible">
    	<!-- Inner Tabs -->
    		<div class="section">
    			<ul class="tabs">
    				<li class="current">inner 1</li>
    				<li>inner 2</li>
    			</ul>
    			<div class="box visible">
    				<h2>inner 1</h2>
    				<p> text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
    			</div>
    			<div class="box">
    				<h2>inner 2</h2>
    				<p> text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text </p>
    			</div>
    		</div>
    	<!--End Inner Tabs-->
    		<h2>1</h2>
    		<p> Закон внешнего мира, как принято считать, реально рассматривается знак, отрицая очевидное. Гегельянство творит катарсис, хотя в официозе принято обратное. Апперцепция подчеркивает смысл жизни, ломая рамки привычных представлений. Представляется логичным, что адживика откровенна.</p>
    	</div>
    
    	<div class="box">
    		<h2>2</h2>
    		<p> Закон внешнего мира, как принято считать, реально рассматривается знак, отрицая очевидное. Гегельянство творит катарсис, хотя в официозе принято обратное. Апперцепция подчеркивает смысл жизни, ломая рамки привычных представлений. Представляется логичным, что адживика откровенна.</p>
    		<p>Априори, закон внешнего мира принимает во внимание естественный гедонизм, ломая рамки привычных представлений. Концепция реально творит гедонизм, учитывая опасность, которую представляли собой писания Дюринга для не окрепшего еще немецкого рабочего движения.</p>
    		<p>Созерцание осмысляет трансцендентальный бабувизм, хотя в официозе принято обратное. Бабувизм абстрактен. Знак, следовательно, понимает под собой субъективный язык образов, ломая рамки привычных представлений. Деонтология непредвзято подчеркивает даосизм, при этом буквы А, В, I, О символизируют соответственно общеутвердительное, общеотрицательное, частноутвердительное и частноотрицательное суждения.</p>
    	</div>
    
    	<div class="box">
    		<h2>3</h2>
    		<p>Структурализм, как следует из вышесказанного, заполняет из ряда вон выходящий дуализм, однако Зигварт считал критерием истинности необходимость и общезначимость, для которых нет никакой опоры в объективном мире. Суждение осмысляет интеллект, однако Зигварт считал критерием истинности необходимость и общезначимость, для которых нет никакой опоры в объективном мире.</p>
    		<p>Сомнение, по определению, непредвзято заполняет знак, изменяя привычную реальность. Современная ситуация, следовательно, подрывает трагический смысл жизни, однако Зигварт считал критерием истинности необходимость и общезначимость, для которых нет никакой опоры в объективном мире. Гносеология категорически порождает и обеспечивает непредвиденный смысл жизни, отрицая очевидное.</p>
    	</div>
    
    	<div class="box">
    		<h2>4</h2>
    		<p>Деонтология создает примитивный даосизм, открывая новые горизонты. Даосизм, как принято считать, амбивалентно представляет собой примитивный структурализм, не учитывая мнения авторитетов. Предмет деятельности транспонирует язык образов, учитывая опасность, которую представляли собой писания Дюринга для не окрепшего еще немецкого рабочего движения.</p>
    		<p>Даосизм, по определению, создает здравый смысл, учитывая опасность, которую представляли собой писания Дюринга для не окрепшего еще немецкого рабочего движения. Сомнение, следовательно, преобразует гений, ломая рамки привычных представлений. Сомнение трогательно наивно.</p>
    		<p>Жизнь откровенна. Предмет деятельности, как следует из вышесказанного, абстрактен. Искусство, как следует из вышесказанного, нетривиально. Гетерономная этика непредвзято понимает под собой смысл жизни, при этом буквы А, В, I, О символизируют соответственно общеутвердительное, общеотрицательное, частноутвердительное и частноотрицательное суждения.</p>
    		<p>Здравый смысл, как принято считать, творит бабувизм, отрицая очевидное. Суждение, следовательно, амбивалентно. Искусство, по определению, подчеркивает данный позитивизм, открывая новые горизонты. Единственной космической субстанцией Гумбольдт считал материю, наделенную внутренней активностью, несмотря на это заблуждение рефлектирует субъективный дуализм, не учитывая мнения авторитетов.</p>
    	</div>
    
    </div>
    

    теперь можно создавать вложенные табы

  3. 3
    ITech

    Ура! Решил у себя проблему с перепрыгиванием в начало страницы при переключении табов! Вот живой пример: http://injoit.com/what-we-do/

    Реализовал твой код, Dimox, на своем сайте с небольшими изменениями. Вся загвоздка в том, что все div.box необходимо обтянуть еще одним div и для него определить фиксированную высоту!

    Так как у меня контент в табах на сайте постоянно меняется, подключил механизм Math.max.apply для расчета максимально возможной высоты вложенного дива .box. Эту высоту и задавал внешнему диву..

    Для эффекта появления использовал вместо show() animate() с указанием четких параметров:

    (function($) {
    $(function() {
    
    	$('ul.tabs').delegate('li:not(.current)', 'click', function() {
    		$(this).addClass('current').siblings().removeClass('current')
    		.parents('div.section').find('div.box').hide().eq($(this).index()).animate({height: 'auto', width: 'auto', opacity: 'show'}, 'slow');
    	})
    
    /*--Определение максимальной высоты для блока-контейнера .box-wrap--*/
    	Array.max = function(array) {
     return Math.max.apply(Math,array);
     };
    	var heights = $('.box-wrap div.box').map(function() {
     return $(this).innerHeight();
     }).get();
    	$(".box-wrap").height(Array.max(heights));
    /*--------*/
    
    })
    })(jQuery)
    

    И собственно HTML:

    <div class="section vertical">
    <ul class="tabs">
    	<li class="current"><span>Mobile</span></li>
    	<li><span>Social and Web</span></li>
    	<li><span>Cloud</span></li>
    </ul>
    <div class="box-wrap">
    <div class="box visible">
    ---
    </div>
    <div class="box">
    ---
    </div>
    <div class="box">
    ---
    </div>
    </div>
    </div>
    

    Не знаю, правильно я сделал или нет, но главное ведь, что оно работает) Буду рад услышать твои комментарии по данному поводу.

  4. 4

    По теме перепрыгивания вверх при переключении табов.
    В комментариях выше был модифицированный скрипт с определением высоты родительского блока, но если например в табы положить меню-аккордеон (оно там прекрасно работает), то при задании фона табам аккордеон будет вылазить за их пределы.
    И так как вся соль заключается в установке определённой высоты блоку-родителю, можно поступить проще:
    Мне лично помогла установка min-height для родительского блока табов.

    .section {
    	min-height: 1px;
    	}

    проверял в ie7> и нормальных браузерах — вроде бы работает.

  5. 5
    maqsim

    Вместо:
    $(‘ul.tabs’).delegate(‘li:not(.current)’, ‘click’, function() {

    Поставьте:
    $(‘ul.tabs li:not(.current)’).live(‘click’, function() {

    Проблема первого элемента в том, что некорректно связываются события через метод delegate, когда разметка с вкладками подгружена через ajax. Второй вариант работает отлично + мы делаем 1 раз выборку, а не 2

  6. 6
    Metaller

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

    Решение — не прятать все табы, а только ненужные:

    .parents('div.section').find('div.box').eq($(this).index()).fadeIn(150).siblings().hide();
    
  7. 7

    Если кому интересно — ещё одно простое решение для перехода к нужному табу по клику на стороннем элементе.

    $('[data-tab-target]').click(function(e) {
    		$("html, body").animate({scrollTop:$('#'+$(this).data('tab-target')).offset().top-50}, 500); //прокручиваем страницу чуть выше положения цели
    		$('#'+$(this).data('tab-target')).trigger('click');
    		return false;
    	});
    <span data-tab-target="tab-2">перейти к табу #tab-2</span>

    у

    <div class="section">
     <ul class="tabs">
     <li class="current">1-я вкладка</li>
     <li id="tab-2">2-я вкладка</li>
     </ul>
     <div class="box visible">
     Содержимое первого блока
     </div>
     <div class="box">
     Содержимое второго блока
     </div>
    </div><!-- .section -->
  8. 8

    Вот код, который это делает (доработан 4-й пример):

    (function($) {
    $(function() {
    
    	$('ul.tabs__caption').on('click', 'li:not(.active)', function() {
    		$(this)
    			.addClass('active').siblings().removeClass('active')
    			.closest('div.tabs').find('div.tabs__content').removeClass('active').eq($(this).index()).addClass('active');
    	});
    
    	var tabIndex = window.location.hash.replace('#tab','')-1;
    	if (tabIndex != -1) {
    		$('ul.tabs__caption li').eq(tabIndex).click();
    		$('html, body').animate({scrollTop: $('div.tabs__content').eq(tabIndex).offset().top - 50}, 700);
    	}
    
    	$('a[href*=#tab]').click(function() {
    		var tabIndex = $(this).attr('href').replace(/(.*)#tab/, '')-1;
    		$('ul.tabs__caption li').eq(tabIndex).click();
    		$('html, body').animate({scrollTop: $('div.tabs__content').eq(tabIndex).offset().top - 50}, 700);
    	});
    
    });
    })(jQuery);

    Число 50 (в двух местах) — это отступ между блоком и верхней границей окна браузера после прокрутки к блоку. 700 — это скорость прокрутки, в данном случае 0,7 секунды.