Раздвижные двери CSS, часть II / Даглас Бауман

В первой части статьи «Раздвижные двери CSS» я предложил новый метод создания визуально привлекательных элементов интерфейса, используя простой, семантический код. Во второй части мы разовьем метод «Раздвижных дверей». Если вы не читали первую часть статьи, самое время сделать это сейчас.

Итак, мы рассмотрим новый сценарий, по которому ни одна из закладок не является «текущей», совместим метод «Раздвижных дверей» с техникой создания ролловера из одного изображения, решим проблему «мертвой» зоны в IE/Win и предложим альтернативный метод обращения к определенным закладкам. Не будем снова повторять суть предлагаемого метода (он изложен в первой части статьи), чтобы сразу перейти к тому, на чем тогда остановились.

Без «текущей» закладки

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

Проблема решается добавлением нижней границы в 1 пиксель для всех «нетекущих» закладок и удалением нижней границы для «текущей» закладки:

#header li {
  float:left;
  background:url("left.gif")
    no-repeat left top;
  margin:0;
  padding:0 0 0 9px;
  border-bottom:1px solid #765;
  }
#header #current {
  background-image:url("left_on.gif");
  border-width:0;
  }

Пример 7 демонстрирует изменения в нашем CSS.

Ролловеры из одного изображения

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

До последнего времени использование любых ролловер-эффектов—будь то созданных при помощи JavaScript или CSS—означало работу с двумя наборами изображений: один—для нормального состояния, другой—для состояния hover. Чтобы избежать задержек, вызванных отдельной загрузкой картинки для состояния hover, существует несколько методов «предварительной загрузки» требуемых изображений в кэш браузера. Petr Stanicek (также известный как “Pixy”) разработал метод «Быстрые ролловеры без предварительной загрузки», в котором оба состояния (нормальное и hover) совмещаются в одном изображении, и, как следствие, исчезает необходимость в предварительной загрузке hover-изображения.

В нашем примере мы разместим оба левых изображения друг над другом, чтобы совместить в одном новом изображении и нормальное, и hover состояния. Сделаем то же самое и для правого изображения. Высота изображений выросла со 150 до 300 пикселей. Теперь у нас есть left_both.gif и right_both.gif и мы можем воспользоваться CSS свойством background-position для подачи в видимый «дверной проем» нужной части нашего совмещенного фонового изображения:

[Когда совмещенное фоновое изображение позиционировано вверху «дверного проема», видимо нормальное состояние. Когда мы сдвигаем фоновое изображение на определенную величину, видимым становится состояние hover.]

Мы подключаем эти два новых изображения к элементу списка и ссылке:

#header li {
  float:left;
  background:url("left_both.gif")
    no-repeat left top;
  margin:0;
  padding:0 0 0 9px;
  border-bottom:1px solid #765;
  }
#header a {
  float:left;
  display:block;
  background:url("right_both.gif")
    no-repeat right top;
  padding:5px 15px 4px 6px;
  text-decoration:none;
  font-weight:bold;
  color:#765;
  }

Работая со свойством background-position, мы должны указать две величины, горизонтальную и вертикальную и именно в таком порядке. Мы не можем совмещать ключевые слова (left, right, top и т.д.), которые мы использовали до этого, с величинами, заданными в процентах или линейных единицах. Поэтому, указывая положение изображения для состояния hover, мы вообще откажемся от ключевых слов. Мы зададим 0% для левого изображения, чтобы его левый край был выровнен по левому краю дверного проема, и 100% для правого изображения для получения противоположного эффекта.

Так как мы знаем точное расположение участков изображения для обоих состояний, мы можем позиционировать фоновые изображения вертикально с точностью до пикселя. Верхние 150 пикселей отвечают за нормальное состояние, а нижние—за состояние hover. Поэтому и для левой, и для правой картинок мы просто сдвигаем фоновые изображения, используя отрицательную величину в 150px. А чтобы обозначить цвет текста только один раз, мы совместим сразу два селектора в нашем новом правиле:

#header li:hover, #header li:hover a {
  background-position:0% -150px;
  color:#333;
  }
#header li:hover a {
  background-position:100% -150px;
  }

Мы можем использовать те же совмещенные изображения для текущей закладки. И не будем задавать новые изображения, как мы это делали раньше, а возьмем «сдвинутое» положение фона, которое мы уже использовали для состояния hover:

#header #current {
  background-position:0% -150px;
  border-width:0;
  }
#header #current a {
  background-position:100% -150px;
  padding-bottom:5px;
  color:#333;
  }

Вот и все, что нужно для реализации ролловеров. Пример 8 демонстрирует ролловеры в действии. Мы сократили общее число используемых изображений с 5 (2 левых, 2 правых и 1 фон позади закладок) до 3 (1 левое, 1 правое и 1 фон), а также избавились от необходимости выполнения предварительной загрузки изображений.

Если вы все это время проверяли результаты нашей работы в Internet Explorer (Win или Mac), вы наверняка заметили, что созданные ролловер-эффекты не работают. Все дело в том, что IE способен применять псевдо класс :hover только к ссылкам и ни к чему больше. Для решения проблемы мы должны были бы вставить дополнительный элемент (например, span) внутрь ссылки и переместить все наши CSS-правила на один уровень внутрь (правила для элемента списка перешли бы на ссылку, а правила для ссылки перешли бы на span).

Мы не будем детально рассматривать поправки, необходимые для обеспечения работоспособности ролловер-эффекта в IE. Но чтобы доказать, что это возможно, мы обратимся к примеру 8а, демонстрирующему вышесказанное. Как видите, смена ролей элементов привела к исчезновению «мертвой» зоны, которую мы упоминали в первой части статьи. Происходит это потому, что ссылка вмещает теперь всю закладку.

Ролловеры—это, как правило, (в большей или меньшей степени) декоративный эффект. Кто-то из вас решит, что требующийся дополнительный код не стоит работоспособности ролловеров в IE. Другие подумают, что добавление кода для обеспечения совместимости со всеми популярными браузерами и решения проблемы «мертвой» зоны—не такая уж и большая жертва. В любом случае, решение за вами. [Пример 8а—единственный пример в статье, который обеспечивает работу ролловера в IE. Дальнейшие примеры используют предыдущий код, не обеспечивающий работоспособности ролловеров в этом браузере.—прим. переводчика]

Решение проблемы интерактивной области

В первой части статьи мы говорили о том, что навигационные ссылки можно превратить в блоковые элементы и, задав дополнительный отступ, увеличить их интерактивную область (область, на которую реагирует при наведении курсор). Визуальная область ссылки чаще всего заполнена фоновым цветом (или фоновым изображением, как в нашем случае), а это подразумевает, что пользователь может щелкнуть мышью в любом месте этой области, а не только на тексте ссылки. В большинстве браузеров, когда ссылка посредством CSS превращается в блоковый элемент, и к этой ссылке применяется дополнительный отступ, ее визуальная и интерактивная области расширяются вместе, покрывая и саму ссылку, и ее отступ. К сожалению IE/Win расширяет только визуальную область, ограничиваясь текстом ссылки в качестве интерактивной области, и не захватывает примененный к ней отступ:

[Интерактивная область в большинстве браузеров расширяется на всю видимую область закладки, но Internet Explorer для Windows делает интерактивным только сам текст.]

В первой части статьи (и совсем недавно после примера 8а выше) мы кратко упоминали небольшое «мертвое» пространство в левой части закладки, вызванное переходом к изображениям с прозрачными уголками. Мы также указали на необходимость избавиться от этой «мертвой» зоны. Однако в первой части статьи мы не останавливались на этом подробно. Браузер IE/Win (версии 6 и ниже) имеет несколько багов в реализации CSS. Один из таких багов создает непреднамеренные—а иногда и не особо заметные—проблемы в удобстве использования (юзабилити) и общедоступности (аксессабилити) навигации на основе CSS.

Указание ширины или высоты для ссылки чудесным образом заставляет IE расширять также и интерактивную область. Но такой шаг нарушил бы гибкую «раздвигаемость» нашего «дверного проема». Вы возможно решите, что в нашем примере с закладками мы могли бы использовать относительную единицу “em”. В этом случае размер наших закладок определялся бы уже унаследованным размером шрифта текста ссылки. Но такое указание высоты для ссылки окончательно сносит башню IE/Win. Кроме того, если только мы не используем моноширинный шрифт, указание ширины в “em” не позволило бы сохранять соразмерность ширины закладки и внутреннего текста при его масштабировании. (Не говоря уже об усилиях по определению подходящей ширины для каждого элемента текста, и необходимости переопределять эту ширину каждый раз при изменении текста закладки.)

К счастью для нас в IE/Win существует другой баг в реализации CSS, который позволяет расширять интерактивную область без необходимости гадать по поводу подходящей ширины. Все что нужно сделать, это задать небольшую ширину для ссылки. Большинство браузеров обратят—и правильно сделают—внимание на заданную для блочного элемента ширину, даже если внутренний контент никак в нее не помещается. Такой элемент сожмется до указанной ширины, даже если это вытолкнет внутренний текст за границы элемента. А вот IE/Win сожмет элемент только до ширины самой длинной строки текста, не содержащей переносов.

Поэтому если мы зададим даже крошечную ширину для ссылки (например, .1em), IE/Win все равно позволит ссылке растянутся на всю ширину внутреннего текста. А кроме того, IE еще и растянет интерактивную область на всю ширину закладки:

#header a {
  float:left;
  display:block;
  width:.1em;
  background:url("right.gif")
    no-repeat right top;
  padding:5px 15px 4px 6px;
  text-decoration:none;
  font-weight:bold;
  color:#765;
  }

Все это кажется полным бредом, так как две этих идеи работают в абсолютно противоположных друг для друга направлениях. Но это работает и решает проблему интерактивной области в IE/Win. Нам нужно помнить, что другие браузеры учтут указанную ширину и попытаются сжать ширину каждой закладки до .1em + отступ. К счастью, IE/Win (версии 6 и ниже) не понимает селектора прямого потомка элемента (CSS child selector), и мы можем использовать его для восстановления ширины ссылки (“auto”) во всех остальных браузерах, что позволит закладкам корректно растягиваться и сжиматься:

#header > ul a {width:auto;}

Пример 9 решает проблему интерактивной области в IE/Win, при этом требующиеся для этого браузера кодовые уловки остаются невидимыми для других браузеров.

Обращение к определенной закладке

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

Вместо использования отдельного id="current" для идентификации текущей закладки, мы можем применить уникальные ID для каждого элемента списка:

<div id="header">
  <ul>
    <li id="nav-home"><a href="#">Home</a>
		</li>
    <li id="nav-news"><a href="#">News</a>
		</li>
    <li id="nav-products"><a href="#">Products</a>
		</li>
    <li id="nav-about"><a href="#">About</a>
		</li>
    <li id="nav-contact"><a href="#">Contact</a>
		</li>
  </ul>
</div>

Мы также применим ID к более крупному элементу-контейнеру (как, например, body). Это значение ID будет соответствовать разделу, к которому относится данная страница [Например, #home для раздела home, #about для раздела about.—прим. переводчика]. Это ID можно будет также использовать для добавления уникальных стилей к другим частям данной страницы. Таким образом, мы сможем изменять внешний вид определенной закладки, если она будет отвечать условию контекстного селектора (descendant selectors). Вместо использования #current как части нашего селектора, мы будем использовать комбинацию ID элемента body и элементов списка для создания условий, при которых закладка будет считаться «текущей»:

#home #nav-home, #news #nav-news,
#products #nav-products, 
#about #nav-about,
#contact #nav-contact {
  background-position:0% -150px;
  border-width:0;
  }
#home #nav-home a, 
#news #nav-news a,
#products #nav-products a, 
#about #nav-about a,
#contact #nav-contact a {
  background-position:100% -150px;
  color:#333;
  padding-bottom:5px;
  }

Пример 10 показывает результат применения id="news" к элементу body, а пример 10а демонстрирует, что происходит, когда элемент body использует id="products". [Навигация сайта A List Apart использует id для элемента body аналогичным образом.—прим. редактора]

Дополнительные замечания

Заголовки блоков: На своем сайте вы, возможно, используете расширяемые модули, которые создают блок вокруг заголовка и соответствующего содержания. Если вы используете контейнер (как, например, div), внутри которого находятся заголовок и контент, у вас уже есть два элемента для каждого фонового изображения (div и заголовок). В этом случае вы, скорее всего, захотите поместить узкое фоновое изображение справа, как показано в примере 2. Это обеспечит вам полный контроль над исходной точкой слева, в которой будет начинаться текст заголовка. Создайте плавный переход нижней части каждого фонового изображения в фоновый цвет содержащего блока и вы получите эффект единого элемента с красивой «шапкой».

Поворачиваем на бок: Если вы можете приблизительно предсказать высоту элемента интерфейса (или если ваше изображение достаточно велико, чтобы «выдержать» вертикальное увеличение), вы можете положить «дверной проем» на бок, используя одно изображение для верхней части, другое—для нижней (вместо левого и правого). В этом случае не забывайте о возможном обильном переносе текста по словам, которое может произойти в случае сужения окна браузера или увеличения размера текста.

«Западание» в IE: Если вы наблюдаете «западание» (исчезновение) фоновых изображений при наведении курсора на закладки в IE/Win, проверьте установки кэша для временных файлов (Сервис > Свойства обозревателя > Общие > Настройка). Вы, возможно, поменяли установку по умолчанию, чтобы быть уверенным, что видите последнюю версию страницы при каждом ее обновлении. IE/Win имеет проблемы с отображением фоновых изображений для ссылок, если вы указали «При каждом посещении страницы». Установка по умолчанию «Автоматически». Она позволяет браузеру мгновенно получать изображение из кэша, предотвращая любые мигания. Большинство пользователей не меняют эту установку, скорее всего, они даже не знают о ее существовании.

Закладки из нескольких слов: Часто бывает, что вам нужно использовать для закладки текст, состоящий из нескольких слов. В этом случае необходимо добавить следующее объявление к правилу ссылки: white-space:nowrap, что поможет избежать переноса текста по словам в некоторых браузерах.

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

Обсудить

Вам понравилось? Обсудите эту статью.

Основатель и глава Stopdesign’а, Даглас Бауман специализируется в простом, ясном и передовом дизайне. Он постоянно бросает вызов существующему положению вещей и расширяет границы того, чего можно добиться, используя существующие веб-стандарты. Даглас был главным архитектором нашумевшего ре-дизайна Wired News в прошлом году. Он обещает, что не будет довольствоваться этой славой.

У вас есть комментарии или замечания по переводу? Направляйте их переводчику—Андрею Смирнову.