Общее руководство по вёрстке

Это небольшое пособие пригодится для всех программистов и верстальщиков. Наши верстальщики в 2014-2015 годах проделали огромную работу, чтобы облегчить нам вёрстку, но время идёт, а в некоторых проектах до сих пор копируется уже заросший мхом код и повторяются одни те же старые ошибки. Такая вёрстка была актуальна для IE8 и ниже, но уже не сегодня.

Вёрстка

  1. БЭМ
  2. Шрифты
  3. Секция "user-content"
  4. Разные мелочи

Скрипты

  1. Модульность
  2. Плагин "Modernizr"

Общее

  1. Стиль кода
  2. Файлы
  3. Sublime Text

Вёрстка


БЭМ

Мы пользуемся методологией модульной вёрстки блок__элемент_модификатор.
Сейчас перечислим наиболее часто встречающиеся ошибки в вёрстке.

1 - Вложенность

Не должно быть имён классов типа: "list__item__image" - это основная ошибка новичков.
Все элементы должны словно лежать на одном уровне; по теории должна быть возможность менять элементы местами и вкладывать их друг в друга как угодно. Также нельзя вкладывать чужой элемент в блок, элементы разных блоков друг в друга и тому подобное.


    <ul class="news-list">
        <li class="news-list__item">
            <div class="news-list__item__left">
                <div class="news-list__item__left__image">
                    <img src="#" alt="Картинка">
                </div>
            </div>
            <div class="news-list__item__right">
                <h2 class="person__title">
                    Заголовок новости
                </h2>
            </div>
        </li>
    </ul>

В этом примере видно две ошибки:
1 - Класс "person__title" взят из чужого блока. Такое наименование блоков идёт в разрез с основой методологии которую мы используем. Нужно "news__title".
2 - Если понадобится поменять стиль заголовка у персоны (где-нибудь на другой странице в блоке "person" с заголовком "person__title"), он поменяется в самых неожиданных местах.
Если хочется использовать один заголовок в разных местах - сделайте отдельный блок заголовка. Но внимание - это будет ближе в "классической" вёрстке, где нет модульности, а всё строится из набора элементов. Также не рекомендуется использовать миксы из БЭМ, так как они достаточно неочевидны.

Вот так будет правильно:


    <ul class="news-list">
        <li class="news-list__item">
            <div class="news-list__left">
                <div class="news-list__image">
                    <img src="#" alt="Картинка">
                </div>
            </div>
            <div class="news-list__right">
                <h2 class="news-list__title">
                    Заголовок правильно свёрстанной новости
                </h2>
            </div>
        </li>
    </ul>

Дополнительным плюсом этого варианта будет лёгкое видоизменение элемента - к примеру, классы "news-list__left" и "news-list__right" делят новость на две части - левую, где будет заголовок и правую с картинкой.
И теперь, если у новости не будет картинки, можно будет просто если убрать узлы с позиционирующими классами, а не добавлять модификатор типа "news-list__item_no-image" и не путать программистов.

Вот пример той же новости, но уже без картинки:


    <ul class="news-list">
        <li class="news-list__item">
            <h2 class="news-list__title">
                Заголовок правильно свёрстанной новости
            </h2>
        </li>
    </ul>

Довольно простое решение для типового списка новостей.

2 - Модификаторы

Иногда начинаем писать: "card-small__item card-small__item_active card-small__item_new" или даже: "b-form__item b-form__item_input b-form__item_error".
Конечно, методология говорит нам писать именно так, но при насаживании это превратится в огромные однотипные пласты кода. Особенно когда дело идёт с таблицами и формами.

Поэтому по необходимости для стилизации можно применять короткие модификаторы состояний с префиксами "is-", "has-".

Модификатор "js-" используется не для стилизации, а только для скриптов. (событий, триггеров и т.п)


    <div class="tabs js-tabs">
        <div class="tabs__item is-opened">
            Контент
        </div>
        <div class="tabs__item">
            Контент
        </div>
        <div class="tabs__item">
            Контент
        </div>
    </div>

Раньше использовались префиксы типа "b-" для определения группы элемента, но они не нужны в имени класса и только занимают лишнее место.

3 - Примеры правильной разметки:

Список новостей - здесь, благодаря правильной структуре, мы можем просто убрать разделение на "news-card__left" и "news-card__right" и получить новость без картинки не используя лишних модификаторов:


    <ul class="news-list">
        <li class="news-list__item">
            <div class="news-card">
                <div class="news-card__left">
                    <div class="news-card__image">
                        <img src="upload/news/1.jpg" alt="img">
                    </div>
                </div>
                <div class="news-card__right">
                    <h2 class="news-card__title">Заголовок новости</h2>
                    <div class="news-card__text">
                        Описание новости...
                    </div>
                </div>
            </div>
        </li>
        <li class="news-list__item">
            <div class="news-card">
                <h2 class="news-card__title">Заголовок новости без картинки</h2>
                <div class="news-card__text">
                    Описание новости...
                </div>
            </div>
        </li>
    </ul>

Форма для отправки сообщений - здесь label и input не имеют классов, так как в этом лучше будет стилизовать теги, чем путать программиста лишними однородными классами:


    <div class="feedback">
        <h2 class="feedback__title">Свяжитесь с нами:</h2>
        <div class="feedback__message">Сообщение при отправке формы</div>

        <form>
            <div class="feedback__item">
                <label for="feedback_name">Ваше имя *</label>
                <input type="text" placeholder="Ваше имя" required="" id="feedback_name" name="name">
            </div>

            <div class="feedback__item">
                <label for="feedback_email">Ваш E-mail *</label>
                <input type="text" placeholder="Ваш E-mail" required="" id="feedback_email" name="email" class="is-error">
                <div class="feedback__error">Надпись при ошибке</div>
            </div>

            <div class="feedback__item">
                <label for="feedback_message">Текст сообщения * </label>
                <textarea placeholder="Текст сообщения" required="" id="feedback_message" name="message"></textarea>
            </div>

            <div class="feedback__item">
                <label for="feedback_captcha">Спам фильтр *</label>

                <div class="captcha">
                    <div class="captcha__left">
                        <div class="captcha__image" title="Нажмите, чтобы обновить изображение">
                            <img src="img/captcha.png" alt="captcha">
                        </div>
                    </div>
                    <div class="captcha__right">
                        <input required="" placeholder="Введите надпись на картинке" id="feedback_captcha" name="captcha" type="text">
                    </div>
                </div>
                
            </div>

            <div class="feedback__item">
                <div class="feedback__button">
                    <button type="submit" class="button button_main" type="submit">Отправить</button>
                </div>
            </div>
        </form>
    </div>

Хорошая модульная вёрстка будет чистой, легко читаемой и расширяемой.

"БЭМ, БЭМ, my baby shot me down... " - Nancy Sinatra

Статьи:

Шрифты

Основные три детали по шрифтам - это форматы файлов, подключение и наименование шрифтов.

1 - Форматы файлов

Для вёрстки типичных сайтов достаточно всего двух форматов - ".woff" и ".eot"; причём второй нужен исключительно для Эксплорера. Ведь когда на сайте подключается по 5-6 разных шрифтов в 4-5 форматах, их размер может достигать 10 мегабайт.

2 - Подключение

НИКОГДА И НИГДЕ, даже в плагинах, не подключаем удалённые шрифты:


    <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">

    @import url('https://fonts.googleapis.com/css?family=Roboto');

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

3 - Наименование

Стоит придерживаться одного стиля наименования семейства шрифтов. Все шрифты лежат в папке шрифтов и разделены на папки по семействам.
Один шрифт - одна папка. В каждой папке по 2 формата каждого начертания. Я советую поступать ещё проще и называть папку по названия семейства, а файлы - только по начертанию.
Затем - в @font-face подключаем шрифт - название внутри подключения должно быть максимально ясным, желательно написанным "CamelCase"-ом или "прописьюбезпробелов".

Правильное использование шрифтов

Структура файлов

    /fonts
    ├opensans
    │├bold.eot
    │├bold.ttf
    │├light.eot
    │├light.ttf
    │├regular.eot
    │└regular.ttf
    └roboto
     ├bold.eot
     ├bold.ttf
     ├light.eot
     ├light.ttf
     ├regular.eot
     └regular.ttf

Подключение

    /* Open Sans */
    /* Обычное начертание */
    @font-face {
        font-family: 'opensans';
        src: url('../fonts/opensans/regular.eot'), url('../fonts/opensans/regular.woff');
    }

    /* Полужирный */
    @font-face {
        font-family: 'opensans';
        src: url('../fonts/opensans/bold.eot'), url('../fonts/opensans/bold.woff');
        font-weight: bold;
    }

    /* Курсив */
    @font-face {
        font-family: 'opensans';
        src: url('../fonts/opensans/italic.eot'), url('../fonts/opensans/italic.woff');
        font-style: italic;
    }

    /* Полужирный курсив */
    @font-face {
        font-family: 'opensans';
        src: url('../fonts/opensans/bold-italic.eot'), url('../fonts/opensans/bold-italic.woff');
        font-weight: bold;
        font-style: italic;
    }

Использование

    /* Подключаем основной и ещё один для страховки */
    html {
        font-family: 'opensans', Arial;
    }

    /* Используем */
    .list__title {
        font-weight: bold;
    }

    .list__info {
        font-style: italic;
    }

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

Секция "user-content"

После сдачи проектов почти всегда наступает одна и та же беда - контент, который идёт от пользователя, конфликтует с вёрсткой сайта. Или при внесении новых элементов могут поломаться уже существующие стили. Чтобы этого избежать, существует хорошее решение - сбросить в файле "reset.css" все стили элементов списков, таблиц и т.д, а внутри блока с классом ".user-content" их нормализовать. Стили этого блока нужно вынести в отдельный файл "user-content.css" чтобы было легче им управлять.


    /* Сброшенный стиль для вёрстки - reset.css */
    ul,
    ol {
        margin: 0;
        padding: 0;
        list-style: none;
    }

    /* Стиль в контенте - user-content.css */
    .user-content ul,
    .user-content ol {
        margin: 1em 0;
        padding-left: 40px;
    }

    .user-content ul li::before {
        content: '';
        /* Стили буллетов... */
    }


В разметке:


    <div class="page__right">
        <section class="user-content">
            <h1>Заголовок</h1>
            <ul>
                <li>Первый</li>
                <li>Второй</li>
                <li>Третий</li>
            </ul>
        </section>
    </div>

Как видно, "user-content" - словно песочница для пользователя, в которой мы легко можем управлять нужными нам правилами, не затрагивая остальной сайт.
Также семантически правильно будет назвать этот тег section, из-за того что внутри могут быть теги h1.

В итоге мы получаем четыре отдельные системы стилей. Первая - сброс стилей; вторая - стили модулей; третья - вёрстка самого сайта; четёёртая - нормализованный контент от пользователя. Но когда верстаем лэндинги, user-content стили не нужны, так как на таких страницах нет определённых мест с контентом.
Список стандартных стилей, которые Firefox добавляет к элементам , Список стандартных стилей в Chrome

Разные мелочи

  1. Необязательно добавлять классы к совершенно каждому элементу в таблице или однообразной форме. Нужно следить за читаемостьи избегать спагетти-кода.
  2. Прижимать футер флексбоксами через поддержку стилей через Modernizr, раньше это делали извращённым и криво работающим способом с фиксированной высотой, теперь можно по правильному.
  3. line-height указывать только относительный, а не в пикселях, чтобы можно было менять размер шрифта.
  4. Когда элемент абсолютный или фиксированный, не забывать указывать z-index.
  5. Тестовый контент от пользователя должен лежать в папке "/uploads", чтобы программист после насаживания мог полностью её удалить и ничего нигде не слетело.
  6. Не стилизовать тег form. Там может быть класс, но только как триггер для js события "submit".
  7. У textarea в стилях должно быть: "resize: vertical" и минимальная высота.
  8. ...

Скрипты


Модульность

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

Если модуль будет вызываться извне - присваиваем эту функцию переменной, внутри воздаём замыкание и возвращаем публичные методы.

Если модуль сложносоставной и делится на подмодули, используем неймспейсы.

Прекрасная статься по модульному js: Модульный подход в JavaScript

Modernizr

Modernizr - плагин для определения, какие технологии поддерживает клиентский браузер.

Идём на сайт, читаем документацию, определяем свой набор и скачиваем. Для большинства работ подойдёт вот такой набор
Здесь он настроен на csall, гриды, флексбоксы, медиа, svg и полифиллы html5. Скачивать полный набор не надо, т.к он будет много весить и в html пропишется море лишних классов.

В html добавляем класс "no-js", на случай если браузер не поддерживает javascript. Далее плагин инициализируется, проверяет, поддерживается ли js, веб-технологии и записывает в html классы, наследуясь от которых можно использовать новые правила. То есть теперь появляется возможность программировать по методикам "Progressive Enhancement" и "Graceful Degradation".

Modernizr - единственный скрипт который подключается в "head" страницы т.к он должен инициализироваться до вывода внешнего вида.

Общее


Стиль кода

Индентация

Отступы всегда должна быть размером в 4 пробела. Никаких табов. Это мешает работать с версионностью.

Форматирование кода

Код должен быть ровным и читаемым. Разделять логические блоки пустой строкой, соблюдать отступы.
Обязательно комментировать js код если он хоть немного неочевиден. Иначе в 99% случаев через очень короткое время никто не сможет разобраться, что там происходит и за что отвечает. Названия функций должны быть ёмкими, чтобы по имени уже можно было понимать что она делает.
js-кода на наших сайтах обычно немного, поэтому его несложно содержать в чистоте.
По всем неоднозначным моментам - Форматирование должно быть схожим с тем, что указано в Zend-стандарте. Прошлая статья из нашей вики

Пример форматирования CSS:


    .element {
        display: inline-block;
        float: left;
    }


Пример форматирования JS:

Модуль кратко описан и названия функцию говорящие, поэтому не нуждаются в комментировании.
Можно указывать переменные через запятую или на каждую переменную по var для лёгкого их перемещения.


    /**
     * Название модуля
     */
    var moduleName = (function() {
        var el = $('.element');
        var closeTrigger = $('.element-close');
        var speed = 400;

        function events() {
            el.on('click', function() {
                openElement();
            });

            closeTrigger.on('click', function(e) {
                e.preventDefault();
                closeElement();
            });
        }

        function openElement() {
            $('.element').addClass('is-opened');
        }

        function closeElement() {
            $('.element').removeClass('is-opened');
        }

        events();

        return {
            open: openElement,
            close: closeElement
        };
    })();


Файлы

Количество файлов и их подключение (спойлер - по 4)

Количество CSS-файлов для обычного сайта которые делаем, должно быть 4. Это:

  1. reset - сброс всех стилей, подключение шрифтов.
  2. plugins - стили всех плагинов в одном файле.
  3. main - основные стили, хелперы, стили пользовательского контента.
  4. user-content - контент, идущий от пользователя.

JS-файлов достаточно тоже 4:

  1. modernizr - должен подключаться в head как уже говорилось ранее.
  2. jquery - на данный момент версия "2.2.4" охватывает максимальное количество браузеров и плагинов. Не нужно подключать две разные версии.
  3. plugins - скрипты всех плагинов.
  4. main - скрипты которые пишем мы сами.
  5. Если рукописный скрипт большой и затрагивает значительную область в работе сайта, его логичнее будет вывести в отдельный файл.

В вёрстке на всех страницах должны быть подключены одни и те же плагины, чтобы не было такого, что один плагин подключён на одной странице, а другой неизвестно где.

И, конечно, подключаем минифицированные версии файлов.

В идеале подключение должно быть в таком порядке:


    <head>

        ...

        <link rel="stylesheet" href="css/reset.min.css"/>
        <link rel="stylesheet" href="css/plugins.min.css"/>
        <link rel="stylesheet" href="css/main.min.css"/>
        <link rel="stylesheet" href="css/user-content.min.css"/>
        <script src="js/modernizr.min.js"></script>
    </head>

    <body>

        ...

        <script src="js/jquery-2.2.4.min.js"></script>
        <script src="js/plugins.min.js"></script>
        <script src="js/main.min.js"></script>
    </body>

Папка вёрстки

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

Sublime Text

Sublime Text лёгкий и быстрый, содержит множество модулей и позволяет легко создавать собственные плагины и сниппеты. Отлично подходит для вёрстки.
Вот некоторые полезные настройки по стилю кода для Sublime Text 3 (preferences/setting):


{
    "auto_complete": false,
    "draw_white_space": "all",
    "highlight_duplicates_enabled": true,
    "translate_tabs_to_spaces": true,
    "word_wrap": false
}

Автор статьи - Дмитрий Сергеевич