Вкладки (страницы) на одной странице на html/css с помощью :target

Рассмотрим один из вариантов создания нескольких страниц или вкладок (в том числе вложенных) на html и css без скриптов, списков и таблиц, на одной html странице. Только дивы, только хардкор. Подходит для небольших портфолио и элементов интерфейса. Не будьте буратинами используя это везде подряд.
Суть:

image

Современные браузеры загружают содержимое только если блок виден, поэтому костыли для загрузки контента (картинок) отменяются.
Коротко: ссылка на блок делает его видимым, при том что по-умолчанию они невидимы (поэтому обратно display:none когда выделяем другие); сделать невидимым первый блок если выделен _не он_, так как по-умолчанию он виден. Собственно, это всё. Теперь реализация.

HTML. Разделим блок на 3 страницы и один на 3 вкладки, для наглядности:

<!-- Блоки, в обратном порядке -->

<!-- Свойства не действительны к элементам, находящимся уровнем ниже (выше - да), "вкладки" придётся делать не вложенными -->

<div id="tab/one"></div>
<div id="tab/two"></div>
<div id="tab/three"></div>

<div id="tab">
<!-- Ссылки можно вынести из блоков в отдельный, но теряется возможность ссылкам влиять друг на друга, поэтому будем их просто заменять для явного выделения (костыль) -->

  <a href="#one">#one</a>
  <a href="#two">#two</a>
<!-- Активная ссылка жирная; делаем ссылку сразу на первую вкладку, иначе придётся делать её видимой по-умолчанию, а это пара ненужных строк в css -->
  <b><a href="#tab/one">#three</a></b>

</div>

<div id="two">
  <a href="#one">#one</a>
  <b><a href="#two">#two</a></b>
  <a href="#tab/one">#three</a>
</div>

<div id="one">
  <b><a href="#one">#one</a></b>
  <a href="#two">#two</a>
  <a href="#tab/one">#three</a>
</div>


Перейдём к разметке, здесь всё внезапно очень просто (но не очевидно) и валидно, никаких нестандартных изощрений:

div {
  display: none; } /* Делаем блок по-умолчанию невидимым */

div:target {
  display: block; } /* Выделенный блок видим */

/* Теперь магия, т.е. регулярные выражения, для удобства */

div[id*=t]:target ~ #one { /* Для всех блоков, содержащих "t" в идентификаторе, делаем #one невидимым */
  display: none; } /* Обошлись одной буквой конкретно в этом случае, иначе придётся просто прописывать "tab" для всех вкладок сразу и отдельно для каждого не-#one */

div[id*=tab]:target ~ #three { /* На последок, для всех вкладок делаем третью страницу видимой */
  display: none; }


Реализовать подобное можно разными способами, но по-моему это самый логичный — без извращений в виде представления ссылок кнопками, списками, скриптами и прочей ересью, ссылка это ссылка, а блок это блок.

Живой пример на codepen
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 35

    +3
    Честно говоря не знал о такой простой реализации. Стыдно. Спасибо, будем использовать.
    • НЛО прилетело и опубликовало эту надпись здесь
        0
        Но и не стоит грустить понапрасну, ибо мой сайт-полуторастраничник работает, а он сделан именно так.
      0
      div:target {
        display: block;
      }
      div[id*=tab]:target {
        display: block;
      }
      div[id*=tab]:target ~ #three {
        display: block;
      }
      div[id*=t]:target ~ #one {
        display: none;
      }
      

      Слоу-мо-css?
      Оно не столько для маленьких страниц, сколько для маленьких проектов. Браузеры читают стили справа-налево, поэтому, если такое попадает в общий файл…брр.
        +3
        Вообще-то это прототип показывающий принципы работы, а вы при разработке больших проектов всегда напрямую копипастите в них код из публичных примеров?

        Тут проблема встанет в том, что при щелчке на ссылку с якорем страница прокручивается до этого якоря на странице, поэтому без перехвата нажатия на ссылку не обойтись, если якоря не в самом вверху страницы.
          +4
          Вообще-то это прототип показывающий принципы работы, а вы при разработке больших проектов всегда напрямую копипастите в них код из публичных примеров?
          Стиль кода и аккуратность важны всегда, если только ты не объясняешь что-то на бумажке в баре.
            +2
            Вай мне!
            Я это написал как раз для тех, кто этого не знает и уже пошел копипастить «клевую фишку».
            Да и как вы это оптимизируете? Обращение по атрибутам да еще и по маске — крайняя степень скорости работы стилей.
            Там айдишники, следовательно, либо на всех страницах соблюдать один нейм-спейс, либо дублировать правила для других айди (указать имена через запятую), либо пользоваться маской, потому что несколько табов на странице станут адом.
            Сам принцип не нов и был на хабре.
            +2
            если такое попадает в общий файл…

            То ничего страшного не произойдёт. В теории рендер будет медленнее, но на практике, заметно это станет только при огромном количество таких селекторов.
            • НЛО прилетело и опубликовало эту надпись здесь
                0
                На счет последний двух и в самом деле не уверен. Будет ли сначала найден айди, а затем искаться после div[id*=t]:target, буду рад, если кто объяснит мне это.
                upd: второй селектор div[id*=tab]:target — без айди.
                  0
                  На практике разницу в скорости будет нереально обнаружить. Что бы отловить разницу нужно будет создать тестовый случай с большим и сложным DOM, а также с огромным количеством сложных селекторов.
                  Кстати, мне не удалось найти примеров таких тестов для более-менее свежих браузеров, единственный который я нашел 2008-го года.
              +4
              Вкладки можно реализовать на чистом CSS с помощью input:checked+div, тогда будет работать даже в ie7. Кроме того, использование :target замусоривает историю переходов браузера, что чаще не нужно.
              А вообще статей на хабре уже было предостаточно — раз, два, три.
                0
                Я свой сайт организовал именно так, в моём случае логично было использовать #portfolio/* для портфолио с соответствующим адресом. Так получилось несколько страниц в одном html файле, без перезагрузки страницы и с загрузкой изображений по необходимости. Это лишь пример, можно использовать для навигации посредственных элементов, те же вкладки в веб-клиенте почты/торрента/настройки и т.д.
                Даже сделал пояснение в самом начале поста:
                Не будьте буратинами используя это везде подряд.
                  +7
                  Вкладки можно реализовать на чистом CSS с помощью input:checked+div, тогда будет работать даже в ie7.
                  Не будет, оба IE9+:
                    +1
                    Упс, извиняюсь за дизинформацию, спутал с селектором CSS "+".
                  • НЛО прилетело и опубликовало эту надпись здесь
                      0
                      Я лишь предложил ещё один вариант вкладок на «чистом CSS», но которая в отличие от предложенного:
                      1) не задействует историю
                      2) позволяет использовать более одной группы вкладок на странице
                      У каждого подхода есть своя область применения, свои достоинства и недостатки. Лично я, за использование небольшого кусочка JS для назначения классов, чем использовать «чистый CSS», при этом генерируя кучу ненужных элементов. Тот, кто отключил JS будет довольствоваться только одной открытой вкладкой, зато возможностей повышения функционала масса.
                        0
                        3) Не занимает атрибут id, который часто требуется заполнить совсем другим.
                        4) Позволяет выделять активную вкладку, без дублирования их в контенте каждой вкладки.
                        • НЛО прилетело и опубликовало эту надпись здесь
                    –7
                    По поводу хардкора автар был прав, страшно представить себе весь проект в таком исполнении. Да, так можно делать, но лучше не стоит (smile)
                      +2
                      Очень странная идея для времени, когда JavaScript есть везде и нужно ещё с бубном потанцевать что бы его насильственно отключить.
                      Но как демонстрация возможностей CSS — неплохо.
                        0
                        Дело в том что это банально понятнее и проще, чем скриптами. Всему свои инструменты.
                          –1
                          Я бы не сказал что понятнее и проще. По мне, проще навесить с помощью jQuery:
                          $('.tab').click(function(){ $('.tab').removeClass('tab-open'); $($(this).attr('href')).addClass('tab-open'); });
                          

                          .tab { display: none; }
                          .tab-open { display: block; }
                          

                          <a href="#tab-1">tab 1</a><a href="#tab-2">tab 2</a>
                          <div id="tab-1" class="tab"></div>
                          <div id="tab-1" class="tab"></div>
                          
                            0
                            Не все проекты используют jQuery. А CSS — все.
                              0
                              Есть отличный фреймворк vanilla.js. Сейчас его из коробки все браузеры поддерживают.
                              var tabs = document.querySelector( '.tab' ),
                                  clickFn = function( e ){ 
                                      tabs.forEach( function( el ){ el.className.replace( /^tab-open\s?|\s?tab-open$|\s?tab-open/g, '' ); });
                                      this.className = this.className.split( ' ' ).concat( 'tab-open' ).join( ' ' );
                                      e.preventDefault();
                                  }; 
                              tabs.forEach( function( tab ){
                                  tab.onclick = clickFn;
                              }
                              

                              Но обычно можно подложить килобайт жс кода, который сделает добавку\удаления класса не через такую особую жопу.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                +1
                                Ну, во-первых, данные селекторы не все устаревшие браузеры поддерживают, поэтому CSS умеют не все, как вы пишите. Во-вторых, я и не настаиваю на jQuery, можно использовать любой другой фреймворк, можно и как указали выше, написать на чистом js, если на то пошло.
                                Зато использование JS:
                                1) избавит от необходимости занимать атрибут id
                                2) даст возможность расширить функционал, если стандартного будет мало (например, выделять активную вкладку).
                              +3
                              Мой мозг минуты три парсил магию CSS из статьи. Вы уверены, что быстрее и проще?
                                +2
                                Можно сделать js скрипт, который будет генерировать такой ксс!
                                  0
                                  Использовать CoffeeScript, компилирующийся в JavaScript, генерирующий такой CSS!
                                    +1
                                    <картинка с дикаприо>
                            +5
                            Я знаю HTML и CSS не так, как хотелось бы, и тут не смог спарсить в голове.

                            Смотрел на пример на codepen, не могу понять — почему у вас есть дивы one, two, three и tab1, tab2, tab3?
                            Почему третий таб у вас состоит из двух дивов (id=tab1 и id=three)?
                            Что такое /one и почему <a href="#tab/one">#three</a>? Третий таб — это на самом деле первый?

                            Извините за глупые вопросы.
                              0
                              1. Дивы #one, #two и #three (заменил на #tab для логичности, по совету одного из товарищей) означают вкладки «верхнего» уровня, #tab/one, #tab/one, #tab/one — вкладки в третьей вкладке, то есть то же самое, но в одном из блоков, для многоуровневого деления.

                              2. #tab — блок, видимый при просмотре всех «вложенных» в него вкладок #tab/* (которые отдельно), для общих элементов при всех #tab/. На примере это светлый фон, мелкий текст и ссылки 3.1, 3.2 и 3.3.

                              3. Переходим сразу на первую вложенную вкладку третьего блока. Её можно сделать по-умолчанию видимой при видимом #tab, но это пара лишних строк в css, правило не обязательное.
                              0
                              jsfiddle.net/hf759a2x/5/ — простой и изящный способ, IE9+
                              • НЛО прилетело и опубликовало эту надпись здесь

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

                              Самое читаемое