Метод html-верстки кнопок с применением псевдоэлементов

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

Выглядело это примерно так:

html

    <div class="large_button">
      <span class="buttons submit_v2-button clickable">
        <i class="left left2"></i>
        <i class="body">
          <b>В архив</b>
          <i class="end">
            <i></i>
          </i>
        </i>
      </span>
    </div>

Видно, что запутаться в таком коде проще простого, тем паче, что вариантов кнопок на проекте накопилось не менее 30. Попытка создать такую кнопку на серверной стороне вызывала негодование у коллег «пехапистов».

Поэтому моей негласной задачей стало максимальное упрощение кода.

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

К сожалению, в этом случае добиться кроссбраузерности несколько сложнее, и ещё мне как пользователю не нравятся CSS-шные тени (как верстальщик я их обожаю).

Решение, которое полностью меня устроило, нашлось в использовании псевдоэлементов :before и :after.

Первым шагом стала систематизация. Все кнопки были отсортированы на группы по размерам, изображениям и основному фону.

Чтобы было совсем хорошо, вся кнопочная графика была объединена в один спрайт.
В итоге это дало приличную экономию в общем объёме изображений и количестве http-запросов.

Надо сказать, что мне очень повезло с коллективом, общими усилиями которого мы со временем отказались от некрофилии поддержки нашего сайта в Internet Explorer 6.

Спустя две недели от вышеуказанного знаменательного события на свет появился совершенно замечательный, на мой взгляд, вариант вёрстки кнопок:

html

    <div class="neobtn-thick">Текст кнопки</div>

css

/* общие свойства для всех кнопок */
*[class*=neobtn]{
    text-shadow: 0 1px 0 #ddd;
    cursor: pointer;
    background-color: transparent;
    display: inline-block;
    background-image: url(../images/buttons/buttons.png);
    white-space: nowrap;
}
    *[class*=neobtn]:before{
        background-image: url(../images/buttons/buttons.png);
        content: '';
        float: left;
    }
    *[class*=neobtn]:after{
        background-image: url(../images/buttons/buttons.png);
        content: '';
        float: right;
    }

/* Персонализация. Создаём кнопку с высотой 46px */
*[class*=neobtn-thick]{
    height: 46px;
    margin: 0 25px 0 45px;
    line-height: 45px;
    font-size: 24px;
    background-position: 0 -153px;
}
    *[class*=neobtn-thick]:before{
        height: 46px;
        width: 45px;
        background-position: 0 -245px;
        margin: 0 0 0 -45px;
    }
    *[class*=neobtn-thick]:after{
        height: 46px;
        width: 25px;
        margin: 0 -25px 0 0;
        background-position: 0 -199px;
    }

/* Добавляем модификации внешнего вида */
        *[class*=neobtn-thick-create]:before{background-position: 0 -291px;}
        *[class*=neobtn-thick-go]:before{background-position: 0 -429px;}
        *[class*=neobtn-thick-down]:before{background-position: 0 -567px;}

Суть метода необычайно проста, чего можно не заметить при беглом его рассмотрении. К любому элементу, у которого в названии класса встречается слово neobtn, мы добавляем базовые «кнопочные» свойства. Затем свойства элемента уточняются добавлением модификаторов (в нашем примере это -thick).
Модифицировать элемент можно сколь угодно, не забывая оставаться в рамках разумного.

Для Internet Explorer 7 код почти такой же, только вместо псевдоэлементов используется метод insertAdjacentHTML для создания нужных нам HTML-элементов, а вместо отступов используется абсолютное позиционирование.

css

*[class*=neobtn]{
    zoom: expression(runtimeStyle.zoom = 1,
    insertAdjacentHTML('afterBegin','<div class="before"></div><div class="after"></div>'));
    position: relative;
    display: inline;
}
.before,
.after{
    background-image: url(../images/buttons/buttons.png);
    top: 0;
    position: absolute;
}

/* BUTTONS */
/* 46px */
    *[class*=neobtn-thick] .before{
        height: 46px;
        width: 45px;
        background-position: 0 -245px;
        left: -45px;
    }
    *[class*=neobtn-thick] .after{
        height: 46px;
        width: 25px;
        right: -25px;
        background-position: 0 -199px;
    }
        *[class*=neobtn-thick-create] .before{
            background-position: 0 -291px;
        }
        *[class*=neobtn-thick-go] .before{
            background-position: 0 -429px;
        }
        *[class*=neobtn-thick-down] .before{
            background-position: 0 -567px;
        }

Этот CSS-код имеет смысл вынести в отдельный файл, подключать его только для пользователей Internet Explorer 7 через условные комментарии, что бы при случае безболезненно от него избавиться:

html

<!--[if IE 7]><link rel="stylesheet" type="text/css" media="screen" href="/css/buttons_ie.css" /><![endif]-->

Небольшие доработки метода позволяют декорировать кнопку типа submit:

html

    <div class="neobtn-thick"><input type="submit" value="Войти" /></div>

css

*[class*=neobtn-thick] input[type=submit]{
  margin: 0 -17px 0 -37px;
  padding: 0 12px 0 33px;
  height: 46px;
  font-size: 100%;
  font-family: Arial;
  text-shadow: 0 1px 0 #ddd;
  color: #222;
}

А при желании вставить произвольное изображение в кнопку, требуется добавить ещё один элемент и сделать желаемую картинку его фоном:

html

<div class="neobtn-thick"><span class="delete"></span>Удалить</div>

css

.delete {
  background url(url);
  width: 00px;
  height: 00px;
  display: inline-block;
}

Вся прелесть этого метода в использовании селектора «звёздочка», что позволяет делать кнопку из любого тега, не опасаясь, что вместо neobtn-thick-create вы напишите trololoNEOBTN-THICK-CREATElo.

Единственная важная проблема в данном случае: придумать первое слово в названии класса так, чтобы оно не являлось частью названия классов других элементов. Например, не стоит использовать очевидные слова типа button или btn. Именно по этой причине в примерах названия классов начинаются с neobtn.

Добавление новых кнопок также не представляет большого труда:

  1. Рисуем новые изображения в общем спрайте
  2. Добавляем в css соответствующие правила
  3. PROFIT!

У метода есть и негативные стороны:

  1. Использование селектора «звёздочка» по идее несколько замедляет процесс отрисовки страницы. Однако стоит заметить, что сколь бы то значимой задержки мне так и не удалось добиться. Количество кнопок на странице не превышает одного-двух десятков, а с учётом сокращения количества тегов, разница в скорости нивелируется.
  2. При масштабировании в режиме «только текст» — всё развалится.

Теоретически можно было бы писать имена классов и модификаторов раздельно:

html

<div class="button button-thick button-thick-create">Создать</div>

но в этом случае возникла бы некая избыточность и тавтология.

В итоге, у меня получилось нечто среднее между передовыми и «классическими» технологиями html-вёрстки.

Указанным методом можно создавать также выпадающие списки, декорировать поля вода и, наверное, ещё много чего.

Пример

Update #1: Подробнее об универсальном селекторе
Update #2: Если вы переживаете из-за селекторов «звёздочка» перед селекторами атрибутов, можно запросто от них избавиться. Вёрстка кнопок при этом не пострадает.