Pull to refresh

Табы на чистом CSS, от IE6+ (реинкарнация одного решения)

Reading time 5 min
Views 12K
Была на Хабре статья о реализации табов на чистом CSS, которую автор удалил (видимо, из-за незавершённости решения), скрыв при этом все комментарии. Благодаря авторской наработке я устранил один из недостатков юзабилити в решении и опубликовал его в комментарии. Поведение табов стало обычным, по клику на табе (или кнопке, смотря как назвать), он выделялся и оставался выделенным после отведения мыши. Чтобы не терять из виду то и другое решение и для продолжения их развития, приведу копии их. Решение автора makzimko скопировано в песочницу (IE9+), сохранив все необходимые свойства. Дополнение — в модификации там же (от IE9+). Новое (UPD3) кроссбраузерное решение с поддержкой от IE6 — на jsfiddle.net и единым файлом. Наконец, при том, что Opera 11.61 работает, для поддержки Оперы 11.50 и младше понадобилось небольшое исправление (UPD4).

(Чем неудобен Хабр — удаление статей, сопровождающееся удалением комментариев. Нельзя быть уверенным, опубликовав комментарий, в том, что он сохранится. Теряется идея краудсорсинга — доработки сообществом изначальных сырых решений, и базы знаний — то, что написал, хранится и для себя, и для других читателей. Несколько больше уверенности придаёт статья, поэтому решение было переопубликовано в статью.)

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

Зачем это нужно? Скорее всего, это решение будет очень кстати для страниц широкого применения, среди клиентов которых попадаются пользователи с отключенным Javascript. Чтобы не делать для них два решения — табы через сервер и табы на JS, можно сделать табы на CSS.
Достоинства, впрочем, видны; перечислим недостатки.

Недостатки исходного решения (часть их решена далее, часть — присуща подходу):
*) нет памяти нажатия кнопки; :focus мог бы помочь, но любой клик по странице потеряет фокус;
*) неподдержка IE8 и ниже (за счёт inline-block; решаемо; решено в UPD3);
*) ограничение высоты контента — за счёт способа решения, необходимо иметь фиксированную высоту для контента, превышение которой приведёт к обрезанию содержимого. (Решение — скролл для каждого внутреннего блока.);
*) немодульность (если не в фрейме) — нельзя использовать как независимый блок на странице, только как окно или фрейм.

Недостатки в дополнении:
Кроме устранения первого недостатка, сохраняются другие и добавляется ещё пара:
*) в дополнении возможно использовать только один ряд табов или кнопок;
*) дублирование контента табов (заголовки).

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

Чтобы правильно смотреть на решение, в URL страницы или фрейма должен быть записан якорь, например, #tab1. Поскольку в песочнице jsfiddle.net якори не предусмотрены, используется маленький скрипт, переключающий на якорь через секунду. В действующем решении его, разумеется, не требуется.

На каком принципе это работает


В HTML без JS мы можем управлять показом содержимого через клики по ссылкам. Способ смены содержимого окна без перезагрузки страницы — это якоря. Страница прокручивается до якоря так, чтобы он расположился у верхнего края окна или фрейма. Всё, что ниже якоря, будет просматриваться в окне или фрейме. Это — основная идея переключения между страницами табов.

Далее, нам нужно скрыть лишнее. В CSS есть свойство overflow: hidden; — ограничитель показа содержимого за пределами блока, и свойство height: ограничитель высоты блока. Нужно указать высоту окна, в котором мы будем наблюдать содержимое (вот оно, ограничение на показ блока — нам нужно содержимое поместить в окно или фрейм и ещё знать, какой высоты будет блок для просмотра). В примере эти 2 свойства указаны в #tabcontent{...}.

Далее, заботимся о показе заголовка с кнопками переключения. Он не должен двигаться при переключении по якорям, поэтому находится снаружи #tabcontent, в блоке #tabs. И нужно закрывать только что нажатые кнопки изображением выбранного неактивного таба. В решении-первоисточнике закрывания не было. Чтобы были перспективы реализации на CSS1, ничем суперсовременным не нужно пользоваться. Приписываем над каждой страницей контента (#tabcontent li) дубль кнопки и изображаем её нажатой. Ставим смещение каждой кнопки вручную так, чтобы при прокрутке по якорю попала точно на позицию только что нажатой кнопки. Приписываем z-index для дубля кнопки так, чтобы она оказалась вверху. (Далее окажется, что для IE6-8 и для остальных это делается немного разными техниками.) Совмещаем кроссбраузерные свойства в едином коде.

В принципе, можно так описать и 2, и 3 ряда табов, если мы точно рассчитаем положение дублирующей кнопки во всех рядах. Если сделать полный дубль заголовков над каждой страницей (нужный таб видимый, остальные невидимые), можно сделать и автоматически заливаемые многострочные табы. Возникает сопутствующий вопрос: красиво ли дублировать контент? Если JS отключён, то другим способом во всех браузерах мы табы не сделаем. Если не отключён, мы с помощью JS на том же решении (ведь дублировать процедуры — это же тоже некрасиво?) продублируем код на клиенте. (В примерах из статьи нет примера полного дублирования контента, это — возможность будущего развития подхода.)

Наконец, обеспечиваем незаворачивание табов на вторую строку, потому что решение у нас однострочное. В 2 примерах выполняется разными способами. В первом (bA9mF/45) — просто свойством white-space: nowrap;, во втором (bA9mF/52) — установлением ширины заголовка, чтобы он был всегда шире всех табов, входящих в него (#tabs{min-width: 573px; *width: 573px;})

Решение


Решение с модификацией проверяется и готово к дальнейшим разработкам здесь: jsfiddle.net/bA9mF/45 (просмотр).
Выглядит так (Fx8-10, Opera11.61, Chrome 16, Safari 5.02 Win):

Показано покрытие кнопкой .pressed последней активной кнопки и реакция на наведение мыши на других кнопках.
В Fx не срабатывает -moz-transition (исправлено в UPD2); в Safari 5.02 в данном примере не отрабатываются градиенты, поэтому выполнено равномерной заливкой (возможно, в более старшей версии нормально). Fx3.6 работает тоже, но без -moz-transition.
Некоторые вариации шрифтов в браузерах скрыты увеличенными кнопками .pressed, но достижимо и точное пиксельное покрытие с несколько другой вёрсткой, и заодно — нормальная реализация в IE7-8. Для этого надо выстроить кнопки по float:left и зафиксировать зазоры между ними, которые сейчас немного плавают из-за inline-block.
UPD: в ЛС сообщили, что в Safari 5.1 всё видно с градиентами в Mac и Win. Тем лучше, теперь код CSS работает с нормальной деградацией (равномерная заливка серым) для Safari 5.0. В стилях применён -webkit-linear-gradient, который введён в Chrome 10+, Safari 5.1+.
UPD 2: По сообщению Softlink, "Транзишн работает в ФФ, но у него есть особенность: если мы меняем позиционирование, то для этого браузера надо обязательно указать начальные координаты." Таким образом, достаточно добавить позицию top:0; в #tabs li, чтобы Fx заработал (его пример здесь).

UPD 3 22.30: Есть решение для всех браузеров. jsfiddle.net/bA9mF/52 (просмотр)
В IE6 есть небольшая естественная деградация — кнопки активны только при непосредственном наведении на ссылку и не работают :hover (и не должны; для реализации в IE6 делают *.htc — файлы). То же самое проявляется и у IE8, если он находится в режиме Browser Mode: Compat, в этом случае у него автоматически включается Document Mode: Ie7, а не Ie8. То же — и в отдельной странице. Поэтому (это общее требование к браузеру IE) нужно убедиться, что браузер не находится в режиме совместимости. (Подробнее о режимах браузера IE см. в обсуждении этой темы с SelenIT2 в комментариях.
Как выглядит страница и эффекты в IE6 и IE7:

UPD 4 13.02 10.30: Opera 10.51, 11.50 — оба решения в версии bA9mF/52 не поддерживаются (прототип работает, хотя на том же принципе). Удивительно: не работает из-за строчки #tabcontent li >div{margin-top: 266px;...}, которую, если убрать, работать будет, а нужна она, чтобы во всех браузерах корректно работало без якоря. Удивительно же то, что без этой строчки везде работает корректно, и в Опере от 10.51 тоже. Быстрый фикс: jsfiddle.net/bA9mF/65/embedded/result Но у Опер (до 11.61) другая незадача: едут наложенные табы при узком окне.
Tags:
Hubs:
+26
Comments 28
Comments Comments 28

Articles