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

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



html
<div class="large_button"><br>  <span class="buttons submit_v2-button clickable"><br>    <i class="left left2"></i><br>    <i class="body"><br>      <b>В архив</b><br>      <i class="end"><br>        <i></i><br>      </i><br>    </i><br>  </span><br></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 через условные комментарии, что бы при случае безболезненно от него избавиться:
<!--[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]{<br>  margin: 0 -17px 0 -37px;<br>  padding: 0 12px 0 33px;<br>  height: 46px;<br>  font-size: 100%;<br>  font-family: Arial;<br>  text-shadow: 0 1px 0 #ddd;<br>  color: #222;<br>}

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

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

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

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

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

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

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

Теоретически можно было бы писать имена классов и модификаторов раздельно:
<div class="button button-thick button-thick-create">Создать</div><br>

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

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

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

Пример

Та же статья на моём сайте.

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