Pull to refresh
VK
Building the Internet

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

Reading time4 min
Views14K
Летом 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:
Total votes 85: ↑54 and ↓31+23
Comments36

Articles

Information

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