Наверх ▲

История одной кнопки: b-form-button.css и b-form-button.js

Елена Глухова Елена Глухова Руководитель группы общих интерфейсов в Симферополе, Яндекс. Варвара Степанова Варвара Степанова Руководитель группы общих интерфейсов в Москве, Яндекс.

Елена Глухова: Здравствуйте, меня зовут Елена Глухова.

Варвара Степанова: А меня Варвара Степанова.

Елена Глухова: Сегодня мы расскажем вам о кнопке, которую Яндекс использует во всех формах, в том числе и в строке поиска.

Варвара Степанова: Мы эту кнопку сверстаем, напишем для нее Javascript, а затем проведем рефакторинг и сделаем кнопку на css3.

Елена Глухова: Что лучше, мы с вами узнаем через полчаса.

Варвара Степанова: Для начала стоит сказать о том, что это вообще за кнопка. Эта кнопка – часть бренда «Яндекса», пользователь должен узнавать ее всегда и везде, независимо от того, каким браузером он пользуется и какая у него операционная система.Из этого вытекает первое требование: кнопка должна быть сверстана абсолютно так же, как и на макете, пиксель в пиксель, во всех браузерах, включая IE6. Наши кнопки умеют адаптироваться под сервис и под цвет фона, который используется в этом сервисе. Особенно хорошо это заметно на кнопке, которая отключена (англ.  disabled).

У кнопки реализованы все те состояния, которые есть у нативного браузерного элемента управления (англ. control). Как и браузерный элемент управления, она может быть вставлена в текст как inline-элемент.

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

Елена Глухова: Итак, что у нас будет внутри кнопки? Так как кнопка должна быть элементом формы (например, находиться в домике), мы решили добавить в нее нативный браузерный элемент управления.

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

Верстать мы будем по БЭМ. БЭМ – это методология, основанная на терминах «блок», «элемент» и «модификатор». Здесь представлена ссылка на статью, в которой рассказывается об этой методологии. Если она вам известна, хорошо, если вам она не знакома, пожалуйста, переходите по ссылке.

Также мы вынесли нашу реализацию на GitHub. Здесь ссылка на репозиторий со всевозможными примерами и реализацией.

Итак, начнем разговор. В терминологии БЭМ кнопка – это блок. Для нее используется выражение “b-form-button”. В файловой системе создается папка, в которой содержимое блока представлено в виде файлов.

Поскольку наша кнопка является элементом формы, то в терминах БЭМ мы будем добавлять в нее элемент “input”. Этот элемент является необязательным. Что это означает? В варианте «кнопка-ссылка» его не будет. Поэтому все стили для необязательного элемента в файловой системе мы выносим в отдельную папку.

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

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

Верстать мы будем в картинках. Текст кнопки может быть любой ширины, туда могут добавляться иконки. Поэтому кнопку нужно «разрезать» на части. Как мы это сделаем? Во-первых, это будет спрайт png-24 с определенным заданным шагом 50 пикселей. В него мы будем добавлять части нашей кнопки следующим образом. Сначала у нас идет левая часть кнопки, правая, а затем середина в обычном (англ. normal)  состоянии. Дальше в определенном заданном порядке идут состояния наведения, активности и так далее – в очень строгом порядке. Этот шаг и эти состояния подойдут как для большой кнопки, так и для кнопки других размеров. То есть спрайт у нас всегда практически одинаковый. Ну, давайте мы ее «порежем».

Возьмем левую часть кнопки и добавим ее в html элементом left. В стилях мы используем b-form-button.css и просто описываем положение формы на нашем спрайте.

То же самое мы  сделаем и с правой частью. Мы тоже можем сделать ее отдельным элементом, но мы решили оптимизировать на разметке, поэтому сам фон мы будем добавлять в самый главный DOM на D b-form-button. Ну, и в css мы пропишем положение в нормальном состоянии для этой части.

Середину кнопки мы будем рисовать элементом “content”. То же самое – b-form-button.css, мы записываем положение и повторение фона в спрайте.

Так как кнопка может быть представлена в разных размерах, то в терминах БЭМ размер – это модификатор. Для обозначения размеров кнопки мы использовали аналогию с размерами одежды – S, M, L и XL. В файловой системе у нас появляется папка size, в которую мы добавляем всевозможные стили для наших размеров. В стилях мы будем задавать непосредственно размер: высоту кнопки, размер шрифта, отступы, высоту строки (англ. line height).

Применительно к кнопке тема – это тоже модификатор, притом составной. Что такое «составной модификатор»? Это значит, что в названии у нас явно указывается зависимость одного блока модификатора от другого. Наша тема зависит от размера, поэтому и называется она grey-m, grey-l и так далее. Также в папку темы (theme) в файловой системе мы добавляем не только стили, но и сам наш спрайт. Обратите внимание, что эти два файла названы одинаково, чтобы не запутаться.

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

Например, когда нам понадобилось сделать новую тему со стрелкой, мы просто сделали новый спрайт и добавили css. Получилось очень быстро. То есть мы как раз реализовали универсальный механизм создания новых тем.

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

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

Так как у нас это все задано в определенном порядке, у нас для всех тем будет одинаковое положение состояний. Их стили выносятся в отдельные папки, и в результате мы получаем вот такую кнопку. Она не статичная, и чтобы ее «оживить», мы напишем Javascript.

Варвара Степанова: Еще нужно отметить, что внутри кнопки есть текст, и в нажатом состоянии этот текст тоже смещается.

Елена Глухова: Да, в нажатом состоянии текст кнопки опускается на 1 пиксель вниз, поэтому мы решили обернуть наш текст в элемент “text”. В состоянии “pressed” мы добавляем один верхний отступ для этого элемента. Таким образом, у нас кнопка нажимается. Это универсально.

Вот теперь время рассказать о том, как мы ее «оживляем» с помощью Javascript.

Варвара Степанова: Теперь напишем Javascript. По правде говоря, нам даже не надо было дожидаться, чтобы css-верстальщик закончил свою работу, потому что Javascript мы писали очень абстрактно. Чтобы начать его писать, нам нужно было знать только, какие элементы-модификаторы будут у нашего блока. Мы будем писать такой Javascript скрипт, чтобы при взаимодействии с пользователем кнопка принимала все реализованные состояния. Кнопка также должна работать как браузерный элемент управления.

Это означает, что кнопка должна…

- поддерживать управление с клавиатуры;

- сообщать о событиях;

- обладать состоянием «неактивна», в котором она не реагирует на действия пользователя.

Чтобы реализовать все это, мы добавляем технологию .js в папку блока. Просто создаем файл Javascript для этого блока. Внутри мы пишем Javascript. Этот Javascript основан на блоке-хелпере i-bem из библиотеки блоков bem-bl. Этот блок позволяет писать другие блоки на Javascript в БЭМ-терминах. По ссылке, которую вы сейчас видите, доступна документация и примеры, иллюстрирующие написание такого Javascript.

По второй ссылке можно посмотреть наши мастер-классы, на которых мы показывали, как писать БЭМ-ориентированный Javascript. Даже если вы эти мастер-классы не смотрели, после нашего доклада, скорее всего, все станет понятно.

Этот Javascript особенный. Там есть ООП-представление. То есть все одинаковые блоки на странице в терминах ООП составляют один класс, а каждый конкретный блок представляет собой экземпляр (англ. instance) этого класса. Мы оперируем предметной областью БЭМ, то есть работаем с БЭМ-сущностями. Например, мы не работаем с CSS-классами, хотя имеем такую возможность, а просто «говорим» ядру, какой модификатор нам нужен. Ядро само работает с классами. То же самое с DOM-структурой – мы с ней практически не работаем, все делаем в абстрактных терминах.

Блок в памяти браузера представляется объектом Javascript, который мы называем БЭМ-объектом. Из этого объекта всегда можно получить доступ к DOM-узлу блока. Благодаря этому всегда можно сделать что-то «по старинке».

Хелперы, предоставляемые блоком i-bem, позволяют работать с модификаторами, со структурой блока и с событиями.

Очень важная особенность Javascript, который мы собираемся написать, это декларативность. Что это значит? У нас есть глобальный объект БЭМ, есть метод “decl”, и мы описываем статические и динамические свойства и методы нашего блока. Когда именно нужно запустить в работу эти методы, ядро определяет само.

Описывать «поведение» нашей кнопки мы будем на языке состояний, а состояния в нашем случае – это модификаторы. Что это означает? Когда меняется состояние (это происходит после какого-либо действия пользователя), у кнопки появляется другой модификатор, это означает, что у нее появляется другой css-класс, и она начинает выглядеть по-другому.

Для смены состояния кнопки не всегда бывает достаточно просто изменения внешнего вида. Иногда нужно отправить какое-то событие или сделать какие-то вычисления, или, может быть, изменить DOM-структуру. Поэтому должен быть какой-то Javascript, который работает между двумя состояниями, при переключении в конкретное состояние.  Такой Javascript позволяет описать эти изменения. 

Для этого мы используем свойство “onSetMod” в секции, касающейся динамической части блока. Здесь указана функция, которая будет исполняться при установке модификатора “mod” для блока в любом значении. При установке модификатора “mod” в любом значении будет срабатывать эта функция.  Также можно реагировать на установку модификатора в конкретном значении.

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

Чтобы это описать, мы пишем метод, который срабатывает на установку модификатора “focused” в значение “yes”.

Для начала мы проверяем, активна наша кнопка или нет. Кнопка может быть неактивна, если у нее есть модификатор “disabled”. Чтобы узнать, есть он или нет, мы воспользуемся методом “hasMod”. Если кнопка неактивна, то мы предотвращаем установку модификатора, обеспечивающего фокус. О том, какая сигнатура у метода “HasMod”,  вы можете узнать прямо из кода, потому что у нас все методы описаны в .js-документах.

Если кнопка все-таки активна, то мы на DOM-элементе, соответствующем блоку, должны «слушать» событие “keydown”, и с помощью функции обратного вызова как-то обрабатывать нажатия. Чтобы «слушать» события на DOM-элементе блока, мы используем метод “bindTo”.

 Напомню, что внутри у нашей кнопки находится нативный браузерный элемент управления. Нужно позаботиться о том, чтобы он тоже был в фокусе. Поэтому мы ищем элемент “input” внутри блока и пользуемся JQuery-функцией “focus”. Для поиска элемента у нас есть метод “elem”, он возвращает JQuery-chain для элементов, которые мы хотим найти. Вообще весь наш мини-фреймворк основан на JQuery, так что всеми JQuery-хелперами можно пользоваться.

Если у нас кнопка не в фокусе, модификатор «фокус» убирается. Для этого нужно сделать все наоборот: перестать «слушать» событие “keydown” и убрать «фокус» у элемента.

Следующее состояние – «неактивная кнопка».  Что для нее характерно?

- Отсутствие реакции.

- Нативный браузерный элемент управления отключен.

Как мы программируем «поведение» блока при установке модификатора “disabled” в любом значении? Сначала мы проверяем, активна наша кнопка или нет. В зависимости от этого мы добавляем или убираем атрибут “disabled” для элемента.

Также необходимо помнить о том, что кнопка иногда бывает ссылкой. Если кнопка неактивна, то по ссылке переходить нельзя. Мы обращаемся к DOM-элементу блока и убираем у него атрибут “href”. При переводе кнопки в активное состояние этот атрибут нужно не забыть вернуть.

Также нужно «стриггерить» на DOM-элементе блока событие “keyup”, чтобы кнопка, которая внезапно стала неактивной, точно не была нажата.

Для того, чтобы выполнять какие-то действия на DOM-элементе блока, мы используем “this” и обращаемся к DOM-элементу блока по ссылке “domElem”. Это JQuery-chain нашего блока.

Поскольку нам часто потребуется проверять, активна кнопка или нет, мы эту проверку «завернули» в хелпер.

Последняя пара модификатора – это «кнопка в нажатом состоянии» и «кнопка в состоянии с наведенным курсором». Эти 2 состояния могут быть у кнопки одновременно.

Эти модификаторы должны…

- сообщать о событиях;

- не работать для неактивной кнопки.

Давайте программировать. Для модификатора “pressed” мы только для активной кнопки «триггерим» на БЭМ-объекте блока “pressed”, если кнопка нажата и “released”, если ее отпустили. Чтобы «стриггерить» событие на БЭМ-объекте блока, мы пользуемся хелпером “trigger”.

События нужны для использования их из других блоков. Функциональность «наведенности» заключается в том, что при отсутствии наведения курсора на кнопку она не может быть нажата. Чтобы она точно не была нажата, мы удаляем модификатор “pressed” с помощью хелпера “delMod”. Мы помним о том, что для неактивной кнопки эти модификаторы применяться не должны. Поэтому мы предотвращаем их установку. В принципе, мы могли бы написать все это в секциях, относящихся к модификаторам “hovered” и “pressed”, но чтобы не пользоваться копированием и вставкой, мы решили все собрать в одном месте и воспользоваться элементом синтаксиса «звездочка». Он позволяет реагировать на установку любого модификатора.

Ну, и самое интересное – это live-события. Многие из вас знают, что это такое. В JQuery был реализован такой метод, который сейчас уже переименован в “on”. Он основан на делегации. Что это означает? Когда событие срабатывает где-то в глубине DOM-дерева, оно «раздувается» (англ. bubble) до документа, и можно «повесить» обработчик (англ. handler) на документ и с помощью одной-единственной функции обратного вызова определять, что нужно сделать по событию.

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

Мы активно пользуемся live-событиями и реализовали свои live-методы. Не только для делегации. Есть еще одна возможность применять их. Чтобы БЭМ-объект Javascript появился в папке браузера, иногда надо выполнить какую-то тяжелую работу. Может быть, произвести какие-то вычисления, что-то «навесить» на событие. Если у нас таких блоков много, и нужно инициализировать их сразу при загрузке страницы, это может быть ощутимо. Хорошо бы инициализировать эти блоки только тогда, когда пользователь начинает с ними взаимодействовать. У нас это реализовано, и называется это live-инициализацией.

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

Наша кнопка должна реагировать на щелчок левой кнопкой мыши, поэтому на документе мы «слушаем» событие “leftclick”, а функцию обратного вызова исполняем при помощи делегации для конкретного блока. «Слушать» событие, делегированное на документе, мы можем при помощи метода “liveBindTo”. Также нам нужно «слушать» события наведения курсора и фокуса, чтобы в тот момент, когда они произошли для кнопки, инициализировать ее и ввести в соответствующее состояние. В зависимости от того, какое событие произошло, у кнопки должен быть тот или иной модификатор. Это знание хранится в специальном хеше “eventsToMods”. Здесь вы видите, что каждому событию соответствует определенное состояние кнопки.

Это все. Кнопка реализована и работает как нативный браузерный элемент управления.

Елена Глухова: Технологии меняются, и мы, конечно же, хотим использовать css3. У нас уходит из поддержки IE6, все большее количество браузеров начинает «понимать» и лучше отображать css3. Поэтому мы решили сделать css3-реализацию. Мы будем делать ее в том же самом блоке “b-form-button”, но для этого нам нужно будет провести небольшой рефакторинг.

Мы введем новый модификатор “type”, в значение  “complex” которого мы перенесем всю нашу старую «картиночную» реализацию, а в значении “normal” мы будем делать новую css3-реализацию.

Также мы в “b-form-button_type_complex.css” перенесем все наши состояния. Используя двойные классы, мы будем управлять положениями картинки. Тут у нас, конечно, нет никаких переменных, просто все это не умещалось на слайд в одну строку, поэтому мы немножко подсократили.

В главном файле “b-form-button.css” у нас остаются только общие стили, которые подходят для обеих реализаций. То есть знание о том, что это inline-блочный элемент у нас будет располагаться именно здесь.

Теперь настало время убрать все лишнее из нашей разметки (теперь оно нам не понадобится). Оставим только элемент “text”, потому что нам нравится, как у нас все нажимается. Также мы оставляем нативный браузерный элемент управления, который нам нужен.

В нашем “b-form-button_type_normal.css”, то есть в нашей css3-реализации мы будем просто задавать закругленные углы, какие-то особенности для неактивного состояния.

Теперь осталось сделать тему для нашей css3-кнопки. Что для этого нужно сделать? Опять воспользуемся составными модификаторами, но на этот раз наш модификатор зависит не от размера, а от типа нашей кнопки.

Как мы делаем стили? Заходим в Интернет, находим любой css3-генератор и копируем оттуда стили. Вот такие стили у нас получились. Правда, они здесь не все. Там есть еще.

Что не так с css3?

К сожалению, получить сходство пиксель-в-пиксель нельзя. Для нас это очень важно, так что отсутствие такой возможности нас расстраивает. Оказывается, когда ты берешь стили из генератора и вставляешь их в браузер, каждый браузер отображает их по-своему. Чтобы получить сходство пиксель-в-пиксель для каждого браузера в отдельности приходится тюнить градиенты, тени и все остальное. Соответственно, быстро создать новую тему в таком режиме нельзя. К примеру, чтобы сделать нашу кнопку со стрелкой, нам бы пришлось добавить новый элемент в разметке, чтобы реализовать такой угол.

Что мы сделали? Давайте вспомним. Мы сверстали кнопку на картинках, написали для нее JavaScript, а также сделали css3-реализацию.

Теперь поговорим о плюсах, только о положительных сторонах каждой реализации.

Что хорошего нам дает css3-реализация?

Во-первых, мы получаем хорошую масштабируемость. Сейчас появляется все больше экранов с хорошим разрешением, как, например, у iPad3. Поэтому масштабируемость кнопки очень важна.

Во-вторых, налицо уменьшение разметки. Это очень хорошо.

В-третьих, у нас нет обращения к серверу за картинкой, - это тоже плюс.

Что хорошего мы получаем от «картиночной» реализации?

Во-первых, мы получаем кнопку пиксель-в-пиксель. Для нас это очень важно.

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

В-третьих, опытным путем мы установили, что «картиночная» реализация рендерится в браузере быстрее по сравнению с css3.

Именно поэтому мы остановили свой выбор на «картиночной» реализации. Она обозначена зеленой галочкой в блоке выводов.

Варвара Степанова: На самом деле мы любим разные «космические» технологии. Мы были бы просто счастливы реализовать все наши кнопки на css3 и использовать их на всем портале. Пока мы себе этого позволить не можем.

Елена Глухова: Мы верим…

Варвара Степанова: css3 – формат развивающийся, он делается прямо сейчас, наверняка кто-то из присутствующих здесь разработчиков прикладывает руку к его созданию. Наш рассказ был нужен в том числе и для того, чтобы объяснить им, что от этого формата нужно такой большой компании, как «Яндекс». Надеюсь, мы предоставили полезную информацию.

Елена Глухова: С вами была Елена Глухова…

Варвара Степанова: … И Варвара Степанова. Спасибо. Ваши вопросы?

Вопросы и ответы

Вопрос из зала: Проблемы знакомые (я по поводу того, что пиксель в пиксель и картинка), но уж если отказались от старых браузеров и посмотрели в сторону css3, почему не base64 хотя бы? Потому что можно отказаться от спрайтов и получить минус запрос к серверу все тот же самый.

Елена Глухова: Думаю, что в этом случае файл будет «весить» очень много, у нас очень много состояний. Конечно, это хорошая идея, ее надо попробовать, пока еще разницы мы не видим. Мы попробуем.

Реплика из зала: Насколько я помню, мы проводили исследования, и на типичных спрайтах потери составили порядка 15 %, что ли, всего-навсего…

Елена Глухова: У нас полупрозрачные спрайты с градиентными границами, то есть смотря какой спрайт будет, тут надо посмотреть.

Вопрос из зала: Добрый день! Вопрос, который я задам, скорее всего, задают довольно часто в связи с БЭМ, но все-таки мне надо его задать. Я видел, что у вас везде там префиксы идут, то есть и у элемента, и у модификатора вы везде пишете префикс. Оказалось столько всего, что даже не влезло на слайд, и так далее. Это же ужасно неудобно, почему вы не используете препроцессор, чтобы не писать их постоянно, ведь это увеличивает количество ошибок, уменьшает информацию в тексте, и так далее?

Варвара Степанова: Препроцессор мы не используем, хотя могли бы. Дело в том, что вручную все эти селекторы в css мы не пишем, потому что мы все файлы элементов, блоков и модификаторов создаем при помощи команды “bem”, у нас есть инструменты БЭМ, у нас есть содержание этого файла по умолчанию, нам остается только применить (англ. apply) правила вовнутрь.

Реплика из зала: Но вы же их читаете и изменяете…

Варвара Степанова: В случае изменения проблемы нет, они уже написаны.

Реплика из зала: Очень часто БЭМ на практике понимается не в значении того, что у нас изолированная верстка, а в значении того, что везде нужно писать префиксы –b и везде делать длинные классы…

Варвара Степанова: Нами это понимается по-другому.

Елена Глухова: Длинные классы, на самом деле, это просто цена понятности. По крайней мере, ты все называешь понятно, и из названия уже ясно, что это такое.

Реплика из зала: Префикс дублируется, потому что выше он у нас все равно определен. Можно все изолированно сделать с помощью префиксов в селекторе. То есть у нас есть какой-то блок, пробел и наш элемент.

Варвара Степанова: Это каскад. А БЭМ для того, чтобы каскада не было.

Реплика из зала: БЭМ для изолированности, каскад – это другая вещь.

Варвара Степанова: Ну, если каскад подразумевает контекстную зависимость, то БЭМ «говорит» о том, что контекстная зависимость – это плохо, и настаивает на том, что мы должны ее избегать. Блоки должны быть независимыми.

Елена Глухова: Это не значит, что мы не используем каскад. Мы его используем, но стараемся это делать как можно реже.

Вопрос из зала: В каком значении контекстная зависимость имеется в виду? Ведь то же самое получается, просто там пробелы и меньше размер классов.

Варвара Степанова: Если у нас будет вложен элемент с таким же именем где-то глубоко внутри другого блока, этот класс подействует и на него тоже. Это контекстная зависимость.

Реплика из зала: Хорошо, спасибо!

Вопрос из зала: Вы несколько раз повторили, что точность до пикселя – это важно. Прошу вас, объясните, почему.

Елена Глухова: Ну, наш дизайнер рисовал это не просто так. Он подбирал этот градиент так, чтобы кнопка не выглядела слишком светлой на светлом фоне и слишком темной на темном. Для нас это как бренд, это наш фирменный стиль, а фирменный стиль всегда важен.

Вопрос из зала: Разница в пиксель или в полтора пикселя не играет роли с точки зрения контраста кнопки на фоне, однако это позволило бы значительно упростить процесс работы с кодом и поддержку этого кода за счет тех «фишек» css3, которые, как вы сами сказали, вам нравятся. Является ли точность до пикселя той ценой, которую стоит платить за удобство?

Варвара Степанова: Это не единственная причина. Мы также говорили про скорость рендеринга и про то, чтобы быстро делать новые темы для кнопки. А точность до пикселя нам тоже важна.

Елена Глухова: И даже очень важна.

Вопрос из зала: А вы не думали использовать нативные псевдоклассы браузеров – “active”, “disabled” и прочие. Понятно, что поддержку старых браузеров надо обеспечить, но для новых можно было бы это использовать. Конечно, и верстку тут придется немного переделать, чтобы эти псевдоклассы использовать для не-А элементов. Эмулировать все это с помощью Javascript затратно. Это первый вопрос. Второй вопрос: как вы проверяете после рефакторинга изменений кода кнопок, как они выглядят во всех браузерах? Вы вручную по ним «проходитесь» или у вас есть какая-то автоматизация – может быть, вы браузер из командной строки запускаете с созданием скриншота, вырезаете и потом сравниваете автоматически. Или вы сами просматриваете, как ваша кнопка выглядит в каждом браузере после каких-то изменений?

Елена Глухова: По первому вопросу. Мы только недавно сделали css3-реализацию, мы ее даже никуда не внедряли. Мы об этом тоже думаем, вполне возможно, что мы скоро сделаем то, о чем вы говорили. У нас в поддержке все еще стоят старые браузеры, на которые мы не можем не ориентироваться, к сожалению.

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

Елена Глухова: Мы, кстати, не сказали, что мы после рефакторинга кнопки никак не изменили Javascript, и он у нас работает точно так же. Это тоже очень важно.

Вопрос из зала: И второй вопрос про тестирование был. Как тестируете?

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

Елена Глухова: Такая система тестирования пока в разработке, и для кнопок мы ее пока не применяли. Скоро мы это будем делать у нас на проектах.

Варвара Степанова: Кнопку мы не тюнили настолько, чтобы тесты надо было запускать.

Елена Глухова: Ну да.

Вопрос из зала: С добрым утром! Спасибо за доклад. У меня несколько вопросов. Мне лучше задать их все сразу или по одному?

Елена Глухова: По одному.

Вопрос из зала:  Хорошо. Идея очень хороша. Изолированная верстка, каждый блок «живет своей жизнью», у него свой css, свой JavaScript. Если мне нужно 50 одинаковых блоков на странице, я их делаю и ничего не меняю, все здорово. Вопрос такой… Допустим, у меня есть 2 блока, которые, с одной стороны, изолированы, но должны быть связаны.  С этим я недавно столкнулся на практике. У меня есть кнопка «Добавить товар в корзину» и есть «Корзина». Они в разных блоках и «живут» отдельной жизнью. Как я по БЭМ должен их «уложить» в файловой системе и где должен лежать файл .js по работе именно с «Корзиной», где должен лежать такой же файл с кнопкой? Вот такой вопрос.

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

Вопрос из зала:  Хорошо. И еще такой вопрос… Существует ли такая вероятность, что проект рано или поздно станет закрытым, и все новые разработки больше не будут выкладываться в общий доступ на GitHub? То есть мы поработаем, на какой-то уровень выйдем, а потом «Яндекс» все это закроет.

Варвара Степанова:  Многое зависит от «Яндекса». Сейчас мы активно выходим на англоязычный рынок, и англоязычные разработчики уже узнали, что такое БЭМ, и скоро узнают еще больше. Даже если нас всех переедет трамвай, БЭМ все равно будет.

Елена Глухова: В общем, мы не бросим, а если что, нам помогут.

Вопрос из зала:  Здравствуйте. Такой вопрос… БЭМ по своей структуре хорошо подходит для автоматизации, есть ли у вас разработки в этом плане? Например, есть ли автоматизация создания тем для кнопок.

Елена Глухова:  Это по «нарезке» спрайта вы имеете в виду, к примеру?

Реплика из зала: Я имею в виду все сразу. Как пример: дизайнер делает спрайт, загружает его и…

Елена Глухова:  …получает новую тему? Нет, пока этого нет. У нас есть автоматизированный инструмент для «нарезки» спрайтов.

Реплика из зала:  Спасибо!

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

Вопрос из зала:  Здравствуйте. Еще один вопрос относительно точности до пикселя и css3. Если для вас это так важно, вы не думали потратить время на создание специального инструмента, который изменяет Text-Shadow в зависимости от браузера, подгоняет под параметры и генерирует вам css?

Варвара Степанова:  Может быть, мы отдадим это на откуп разработчикам браузеров? Чтобы не надо было подгонять.

Реплика из зала:  Не знаю, опыт показывает, что ждать от них чего-то не лучшая идея.

Варвара Степанова: Ну почему, мы вот тут все намекаем и намекаем.

Реплика из зала:  Окей, окей. Понятно.

Вопрос из зала:  Задам вопрос, который связан с некоторыми другими вопросами. Есть ситуация с ужасным слайдом с кучей исходников и с генераторами css. Почему вы все-таки не используете препроцессоры, которые позволили бы вам создавать css3-свойства без этих генераторов? Вы могли бы потом их править и нормально читать, нормально генерировать линейные градиенты в том числе, вносить небольшие исправления (это вообще очень просто делается). Тут, помимо прочего, еще куча других преимуществ. И префиксы вы бы не писали.

Варвара Степанова: Градиенты Photoshop, которыми пользуются дизайнеры, не являются линейными. Поэтому даже если мы придумаем механизм, который что-то рисует, мы все равно потратим усилия, притом неизвестно, зачем. Все равно все это придется тюнить, потому что искусственный интеллект еще не изобрели. Легче использовать сторонний генератор и потом подтюнивать.

Вопрос из зала: У меня несколько коротких вопросов. Вы пробовали “border image” использовать вместо спрайтов для css3-кнопки?  Я предлагаю комбинированный подход: взять “border image” и применить его вместо градиентов.

Елена Глухова: Нет, не пробовали.

Реплика из зала: Это позволит убрать лишние элементы, очень неплохой “foldback” получается.

Елена Глухова: Нет, у нас в css3 нет лишних элементов. У нас там только то, что надо.

Реплика из зала: Нет, я вот что имею в виду… Вы сможете убрать лишние элементы и использовать картинки. То есть точность до пикселя вы получите.

Елена Глухова: У нас в поддержке есть браузеры, которые «не поймут» применения “border image”.

Реплика из зала:  Я имею в виду, что css3-версию можно сделать с “border image”.

Елена Глухова: Да, это можно попробовать.

Вопрос из зала: Получилось ли у вас сделать адекватную стрелку вправо на css3?

Елена Глухова: Нет, я даже не пыталась. Я поняла, что там нужно что-то сложное делать.

Вопрос из зала: Понятно, спасибо. Почему использован input type button, а не просто button-элемент?

Елена Глухова:  Вообще-то у нас была кнопка именно на button-тэг, мы от нее отказались, уже не помню, что с ней было связано.

Реплика из зала:  То есть были какие-то проблемы…

Елена Глухова:  Да, были какие-то проблемы, и эта реализация намного лучше.

Реплика из зала:  Окей, спасибо.
G

Комментарии

Нет ни одного комментария

Только пользователи могут оставлять комментарии

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

Адриан Крупчанский

Адриан Крупчанский

Бизнесмен, руководитель компании «Нотамедиа», проектов «Москва, которой нет», «Энциклопедия нашего детства» и других.

Я хотел бы вам рассказать, что написано в великом трактате Патанджали Муни, который называется «Йога-сутры». Йога – это успокоение ума. Кто-то хочет успокоить свой ум?

Иван Песин

Иван Песин

Технический директор компании "N-iX".

Немного о том, как мы думаем, и о том, какое это имеет отношение ко всему, что мы делаем.

Валентин Нечаев

Валентин Нечаев

Ведущий инженер по разработке программного обеспечения в компании «Massive Solutions Ltd».

Валентин Нечаев (Massive Solutions Inc.) рассказывает о проблемах мониторинга современных вычислительных кластеров.