Pull to refresh
VK
Building the Internet

Как мы разрабатывали темы для Почты

Reading time 4 min
Views 14K
Летом 2011 года мы внедрили новый дизайн Почты Mail.Ru. Интерфейс изменился не только визуально, но и был полностью переделан в техническом плане, что в разы ускорило его быстродействие и удобство. Но еще это было необходимо для реализации очень желанной для пользователей фичи — тем оформления интерфейса. О том, как мы внедряли темы в Почте, хочу рассказать в этом посте.



Буквально за неделю до этого мы закончили перевод основных страниц на БЭМ (http://bem.github.com/bem-method/pages/beginning/beginning.ru.html). Решено было делать тематическую кастомизацию почты только на CSS. Но чистого CSS мало, нужен инструмент генерации CSS – и мы выбрали SASS (http://sass-lang.com/).

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

/css
 /blocks
    /messages
    ...
 /pages
    main.css


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

Тема – это картинки на фоне, а также цвета (шрифт, фон, бордер...). Мы брали блок за блоком и выносили всю цветовую часть отдельно.

/css
 /blocks
    /messages // геометрия блоков
 /themes
    /default
       /messages // файлы с переменными оформления
       default.scss // сборка всех блоков с переменными
       default.vars.scss // значения переменных по умолчанию
    /theme
       theme.scss // файл с нужными инклудами
       theme.vars.scss // “окрас” конкретной темы
 /pages
    …


Естественно, нам понадобилась система сборки. SASS подошел. Он позволяет собирать scss в один большой css-файл плюс дает возможность использовать переменные.

Стилевое оформление одного из блоков строится так:

/css/blocks/messages/messages.scss
.messages{
        	padding:20px;
}

/css/pages/mail.scss
@import url(../messages/messages.scss);

/css/themes/default/messages/messages.scss
.messages{
 background:$messages-background;
}

/css/blocks/default/default.scss
@import url(messages/messages.scss);


В этих стилевых файлах все значения css-свойств – переменные, которые определяются в конкретной теме.

/css/themes/theme/theme.vars.scss
$messages-background: #FFF;

/css/themes/theme/theme.scss
@import url(theme.vars.scss);
@import url(../default/default.scss);


После работы SASS мы получаем файл с геометрией всех блоков:

/css/pages/mail.css


и файлы с цветовым оформлением, разбитые по темам:

/css/themes/theme/theme.css;


Пользователю загружаются два файла – геометрия и стили выбранной темы.

Переключение темы

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

Для работы с темами создан JS-класс, основными интересующими нас методами которого являются setTheme и switchThemeCss.

Система обратных вызовов для асинхронной работы с темами построена с помощью deferred.

Метод setTheme – “точка входа” для установки темы. Принимает id темы и возвращает deferred, который ожидает выполнения двух методов: switchThemeCss (смена стилей темы оформления) и AJAX-запрос на сохранение выбранной темы. Оба эти метода тоже работают с deferred.

return $.when(AJAX.post(...), switchThemeCss(themeId));


Самое интересное происходит внутри switchThemeCss. Основываясь на переданном themeId, функция строит путь до файла стилей и пытается его загрузить.

В проекте к этому моменту уже использовался плагин для загрузки стилей jquery.getCSS, и мы решили им воспользоваться. Но, к сожалению, он не позволяет определить, действительно ли загрузились стили, или запрос “отвалился” по таймауту из-за отсутствия подключения к сети, что очень важно для нас, т.к. удалять стили старой темы нужно только после успешного применения стилей новой.

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

На страницу добавляется скрытый блок, на который “навешиваются” стили, уникальные для каждой темы. После загрузки файла стилей проверяем, изменились ли стили скрытого блока, и если изменились – значит, тема успешно загружена.

В нашем случае 100% уникальность имеет id темы. Но этот id не имеет ничего общего с возможными значениями CSS-свойств, а значит, в общем случае стили применены не будут.

Нужно было некоторое свойство, значением которого может быть произвольная строка. Для этого подходят свойства content и font-family, но с некоторыми оговорками.

Одни браузеры не применяют свойство content к не псевдо-элементам, для которых оно предназначено. А другие не применяют свойство font-family, если такого семейства в реальности не существует, но при этом применяют свойство content. Мы решили использовать оба свойства, и в браузерах, которые возвращают пустое значение свойства content, смотреть в свойство font-family.

В итоге получился примерно следующий код (схематично):


function getApplyedThemeId(){
        	var ff = hiddenElement.css('font-family'),
        	     content = hiddenElement.css('content');

return content || ff;
},

function switchThemeCss (themeId){
        	var   url = getThemeCssUrl(themeId)
                    	, deferred = newDeferred();

        	var oldThemeId = getApplyedThemeId(); // Получаем текущий themeId
        	$.getCSS(
                    	url,
                    	function(link){
                               	var newThemeId =getApplyedThemeId(); // Получаем новый themeId
                               	// Если id не совпадают – тема загрузилась
                               	if (newThemeId !== oldThemeId){
                                           	$ThemeCSS.remove(); // Удаляем старые стили
                                           	$ThemeCSS = $(link); // Запоминаем новые
                                           	deferred.resolve(); // Возвращаем ОК
                               	} else { // Тема по какой-то причине не загрузилась
                                           	$(link).remove(); // Удаляем link на неудачные стили
                                           	deferred.reject(); // Возвращаем “все плохо”
                               	}

                    	}
        	);
}


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

На техническую реализацию, создание 12 тем, отладку и выпуск на продакшн ушло 2 месяца работы одного человека.

Напоследок — забавная статистика о самых популярных темах:

Зомби устанавливают в основном мальчики 12-25. А еще это любимая темы команды Почты Mail.ru:)


Игра в снежки удерживает лидерство в сегменте тем про зиму, на данный момент ее установили уже более 300 000 человек, 2/3 из которых представительницы прекрасного пола 25-34


Самая девчачья тема Анимэ (девочки 12-17 лет)


Самая гиковская тема — Blackboard. Включить ее из интерфейса вообще нельзя! Зато можно включить вот по такой читерской ссылке http://e.mail.ru/cgi-bin/msglist?folder=0&setTheme=t1026

Саймонс Кэт — темы для молодых женщин 25-34


P.S: Приоткрывая завесу тайны — в ближайшее время выйдут первые две темы для фанатов игр Аллоды и Легенда.

Андрей Сумин,
руководитель разработки клиентской части
Tags:
Hubs:
+23
Comments 36
Comments Comments 36

Articles

Information

Website
vk.com
Registered
Founded
Employees
5,001–10,000 employees
Location
Россия
Representative
Миша Берггрен