Войти с помощью github
Форум /

 

[первая часть] - [вторая часть] - [третья часть]

Самое начало (Яндекс.Адреса)

Когда я начал работать над Яндекс.Адресами в далёком 2005 году, вёрстку я делал так:

Делались статические HTML-странички (index.html, about.html), стили для них складывались в один CSS-файл (adresa.css), скрипты в adresa.js, а картинки в директорию i (i/yandex.png, i/hint.png, etc).

Хаки для MSIE писались в этом же файле через * html и [id].

    about.html
    index.html
    ...
    adresa.css
    adresa.js
    i/
        yandex.png

Все стили были в одном файле, и для их визуального разделения в коде использовались комментарии с указанием начала и конца этой части.

/* Content container (begin) */
    #body
    {
        font: 0.8em Arial, sans-serif;
   
        margin: 0.5em 1.95% 0.5em 2%;
    }
/* Content container (end) */

/* Graphical banner (begin) */
    .banner
    {
        text-align: center;
    }
   
    .banner a
    {
        text-decoration: none;
    }
/* Graphical banner (end) */

Свёрстанные статические HTML-странички нарезались в XSL, который использовался в продакшене. Правки HTML, которые вносились в XSL, вручную переносились в HTML, для поддержания статики в актуальном состоянии.

Проекты большего размера (Яндекс.Музыка, Яру)

Адреса были маленьким проектом с несколькими страницами и там такой подход к вёрстке работал.

При вёрстке первой версии Яндекс.Музыки в начале 2006 стало понятно, что для проекта с большим количеством страниц такой подход к верстке не работает. Тяжело подбирать названия классам, так, чтобы они не пересекались с классами на других страницах. Код всего проекта сложно держать в голове и писать его так, чтобы изменения на одной странице ничего не ломали на другой странице.

Типичный код того времени:

/* Albums (begin) */
    .result .albums .info
    {
        padding-right: 8.5em;
    }

    .result .albums .title
    {
        float: left;

        padding-bottom: 0.3em;
    }

    .result .albums .album .listen
    {
        float: left;

        padding: 0.3em 1em 0 1em;
    }

    .result .albums .album .buy
    {
        float: left;

        padding: 0.4em 1em 0 1.6em;
    }

    .result .albums .info i
    {
        font-size: 85%;
    }
/* Albums (end) */

И вот ещё пример:

/* Картинки на фоне (begin) */
    .b-foot div
    {
        height: 71px;
   
        background: transparent url(../i/foot-1.png) 4% 50% no-repeat;
    }
   
    .b-foot div div
    {
        background-position: 21%;
        background-image: url(../i/foot-2.png);
    }
   
    .b-foot div div div
    {
        background-position: 38%;
        background-image: url(../i/foot-3.png);
    }
   
    .b-foot div div div div
    {
        background-position: 54%;
        background-image: url(../i/foot-4.png);
    }
   
    .b-foot div div div div div
    {
        background-position: 71%;
        background-image: url(../i/foot-5.png);
    }
   
    .b-foot div div div div div div
    {
        background-position: 87%;
        background-image: url(../i/foot-6.png);
    }
/* Картинки на фоне (end) */

Одновременно с Музыкой началась вёрстка Яндекс.Друзей (сейчас это Яру). Это был проект с десятками страниц и такой подход к верстке не работал — вёрстка становилась неуправляемой.

Поэтому части страниц, которые имеют самостоятельное значение в дизайне проекта, стали называть блоками. Корневые классы блоков получили префиксы (b-, c-, g-). Внутренние классы блоков писали без префиксов.

    Используемые префиксы:

    b-  block
        независимый блок, может использоваться в любом месте страницы

    с-  control
        контрол (независимый блок) с которым ассоциирован javascript
        объект, обеспечивающий его функциональность, может использоваться
        в любом месте страницы

    g-  global
        глобальное определение, используется по необходимости, количество
        сведено к минимуму


    Используемые постфиксы:

    -nojs  no javascript
        стиль применяется в отсутствие javascript, если javascript
        включен, то при загрузке страницы у всех элементов этот
        постфикс убирается, для этого должен быть вызван метод init() в onload

Элементы у которых много кода, обрамляются в коде своими комментариями с маркерами начала и конца:

/* Head (begin) */
    .b-head { ... }

    /* Logo (begin) */
        .b-head .logo { ... }
        .b-head .logo a { ... }
    /* Logo (end) */

    /* Right side (begin) */
        .b-head .right { ... }
   
        /* Info (begin) */
            .b-head .info { ... }
            .b-head .info .exit a { ... }
        /* Info (end) */
   
        /* Search (begin) */
            .b-head .search { ... }
            .b-head .search div div, .b-head .search div div i { ... }
        /* Search (end) */

    /* Right side (end) */

/* Head (end) */

Стили кладутся в директорию css (css/music.css), скрипты в js (js/music.js).

Валидные хаки для MSIE пишутся в основном CSS-файле:

/* Common definitions (begin) */
    body
    {
        font-family: Arial, sans-serif;
        font-size: 0.8em;
       
        padding: 0 0 2em 0;
        background: #fff;
    }
   
    * html body
    {
        font-size: 80%;
    }
   
    ...

/* Common definitions (end) */

Невалидные хаки уносятся в файл css/music-ie.css:

/* Common blocks (begin) */

    /* Artist (begin) */

        .b-artist .i i
            {
                top: expression(7 + (90 - this.parentNode.getElementsByTagName('img')[0].height)/2);
                filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../i/sticker-lt.png', sizingMethod='crop');
            }

        ...

Структура проекта выглядит следующим образом:

    about.html
    index.html
    css/
        music.css
        music-ie.css
    js/
        music.js
    i/
     yandex.png

Зачатки общепортального фреймворка

Когда верстаешь несколько проектов одновременно, появляются общие блоки, которые растут и меняются вместе с проектами. Очень быстро понимаешь, что copy/paste этих блоков с проекта на проект не выход и надо делать некоторый common, куда уносить общее.

Так появляется общее хранилище, в которые складываются стили шапки, статического текста и т.д.

Эти стили подключаются в основной проектный файл с помощью импортов:

@import url(http://common.cloudkill.yandex.ru/css/global.css);
@import url(http://common.cloudkill.yandex.ru/css/head/common.css);
@import url(http://common.cloudkill.yandex.ru/css/static-text.css);
@import url(http://common.cloudkill.yandex.ru/css/list/hlist.css);
@import url(http://common.cloudkill.yandex.ru/css/list/hlist-middot.css);
@import url(http://common.cloudkill.yandex.ru/css/dropdown/dropdown.css);
@import url(http://common.cloudkill.yandex.ru/css/dropdown/dropdown-arrow.css);
@import url(http://common.cloudkill.yandex.ru/css/foot/common-absolute.css);
@import url(http://common.cloudkill.yandex.ru/css/foot/common-absolute-4-columns.css);
@import url(slider.css);

/* Header (begin) */

    /* Service (begin) */
        .b-head .service h1 { ... }
        .b-head .service h1, .b-head .service h1 a, .b-head .service h1 b { ... }
    ...

Чтобы с этим можно было уйти в продакшн, появляется процесс сборки проекта, во время которого вместо @import подставляется содержимое этих файлов.

Вёрстка независимыми блоками (доклад на ClientSide'2007)

К осени 2007 года правила вёрстки уже устоялись и о них захотелось рассказать вне Яндекса.

На ClientSide'2007 я сделал доклад «Вёрстка независимыми блоками»

Блок

В докладе вводится понятие «Блок»:

Блоком будем называть фрагмент страницы, который описывается своей разметкой и стилями.
Правила независимости блока

Формулируются правила независимости блока:

1) для описания элемента используется class, но не id
2) каждый блок имеет префикс
3) в таблице стилей нет классов вне блоков


Отказ от использования id даёт возможность использовать один и тот же блок несколько раз на странице. Так же позволяет использовать несколько классов на одном DOM-узле, что в дальнейшем нам пригодилось.
Более позднее описание в клубе БЭМ: http://clubs.ya.ru/bem/replies.xml?item_no=4

Простые и составные блоки

Блоки делятся на простые и составные.
В простые блоки нельзя вкладывать другие блоки, в составные — можно. Это было очень наивное деление, даже в самые простые блоки вкладывались другие блоки и приходилось переделывать вёрстку, потому что простые блоки верстались с использованием имён html-элементов в селекторах.

Более позднее описание в клубе БЭМ: http://clubs.ya.ru/bem/replies.xml?item_no=42

Правила полной независимости блоков

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

1) никогда не опираться на элементы, только на классы: .b-user b -> .b-user .first-letter
2) всем классам внутри блока давать имена начинающиеся с имени этого блока: .b-user .first-letter -> .b-user-first_letter


Позже мы назвали это АНБ (абсолютно-независимые блоки): http://clubs.ya.ru/bem/replies.xml?item_no=43

Сейчас все блоки делаются в АНБ-нотации, но на тот момент мы считали, что так раздувать html-код дорого и надо этот подход применять только в исключительных случаях.

Префиксы

Имена блоков начинаются с префиксов. На тот момент использовались префиксы b-, h-, l-, g-

Модификация блоков

Определились правила изменения внешнего вида блока:

  1. Модификация блока от контекста — блок меняет свой внешний вид в зависимости от того в какой контекст он помещён
  2. Модификация постфиксом — добавляя постфикс имени блока (b-block b-block-postfix) и используя дополнительные классы в HTML



[первая часть] - [вторая часть] - [третья часть]