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

Сергей Осокин
Дизайн-кабак
7 min readMar 20, 2020

--

Должен ли дизайнер уметь программировать? На этот вопрос вываливается куча статей в поисковиках, где у авторов приводятся похожие аргументы «за» и «против». Иногда в комментариях появляются разработчики, которые критикуют дизайнеров, лезущих не в своё дело.

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

Немного обо мне и коде

Я графический дизайнер и иллюстратор, который знаком с программированием. Я немного разбираюсь в HTML, CSS, JavaScript, знаком с PHP и работой с Xcode.

Знания не раз помогали в коммерческих проектах, связанных с веб-дизайном. В свободное время создаю скрипты для Иллюстратора и Фотошопа, написал расширения для Хрома Open in Figma, Open in Notion. Я не обладаю какими-то сверх глубокими познаниями в коде, но могу написать что-то простое самостоятельно, не тратя время знакомых разработчиков.

Предыстория

В конце 2019 мы с продуктовой и маркетинговой командами Модульбанка применили систему аналитики Микспанель в новом для себя ключе.

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

На первый взгляд попап выглядит вполне сносно

CSS и кастомизация

В ходе первых тестов обнаружился первый минус. Превью в редакторе Микспанели далёк от реальности. Во время отправки тестового варианта мы обнаружили сильные отличия:

Ожидание-реальность: попап Микспанели из маленького окна внезапно превратился в огромный баннер с шириной 800 пикселей

С этим связан второй минус. Оказалось, что в Микспанели нельзя настраивать свои CSS стили. Это довольно грустно для современного сервиса, а нам необходимо было стилизовать попап под интерфейс нашего продукта.

Джон тоже не понимает, где кастомизация CSS?

Как решили

Я подготовил редизайн уведомлений на базе имеющихся продуктовых компонентов в Фигме, а верстальщик сделал единственно возможное в этой ситуации — проанализировал все CSS стили окна Микспанели и переписал каждый.

Когда попап из Микспанели попадает в личный кабинет пользователя, стили на лету меняются. Костыль, но куда деваться:

Поп-ап после редизайна

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

Так пришла идея реализовать на базе кода от верстальщиков обычную html-страничку с формой ввода текста для попапа и изображения. В данном случае обращаться к коллегам по такой мелочи нелогично: у всех задачи расписаны наперёд. Просить помочь в нерабочее время — можно, но неприлично. А так как знания программирования у меня имеются, то эта идея крепко засела в моей голове.

Генератор v1. Начало

На первом этапе в html с попапом я решил добавить простенькую форму из пары полей <textarea>, чтобы можно было вводить заголовок и описание в несколько строк и обычным <input> для текста кнопки. Здесь и далее я буду приводить только куски кода непосредственно генератора.

<div class="txt-form">
<textarea id="myTitle" maxlength="30" rows="2" cols="45" placeholder="Заголовок"></textarea>
<textarea id="myDesc" maxlength="250" rows="5" cols="45" placeholder="Описание"></textarea>
<input type="text" id="myBtn" placeholder="Кнопка">
<button onclick="submitTxt()">Просмотреть</button>
<button onclick="resetPage()">Сбросить</button>
</div>
Первая версия страницы генератора

Кнопка «Просмотреть» для подставки текста в попап. Зачем для предпросмотра было делать отдельную кнопку, добавляя на пути пользователя лишний клик? На тот момент мне эта кнопка казалась логичной, но позже я её выпилил.

После клика на «Просмотреть» функция submitTxt() брала значение из полей ввода по ID и подставляла также по ID в соответствующие блоки попапа на странице:

function submitTxt() {
var title = $("#myTitle").val();
var descr = $("#myDesc").val();
var btn = $("#myBtn").val();
$("#mixpanel-notification-title").html(nl2br(title));
$("#mixpanel-notification-body").html(nl2br(descr));
$("#mixpanel-notification-button-link").text(btn);
}

Проблема в том, что хоть <textarea>и поддерживает перенос строк, но при подставке в попап эти переносы исчезали и текст шёл в одну строку.

Покопавшись, я узнал о существовании функции nl2br(), которая преобразует перенос строки в html-код. Поэтому наш текст вставляется в попап после промежуточной обработки этой функцией:

function nl2br (str, replaceMode) {
var breakTag = "<br>";
var replaceStr = (replaceMode) ? "$1"+ breakTag : "$1"+ breakTag +"$2";
return (str + "").replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, replaceStr);
}

Кнопка «Сбросить» вызывает перезагрузку страницы.

function resetPage() {
window.location.reload(false);
}
Работа первой версии генератора

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

Генератор v2. Эволюция

Прошло пару месяцев и в феврале 2020 я набрался сил для улучшений функционала и рефакторинга кода. В планах было:

  • сразу видеть результат ввода текста;
  • подгружать иллюстрации через форму;
  • скачивать попап в png, чтобы пересылать внутренним заказчикам на согласование.
<div class="txt-form">
<textarea id="myTitle" maxlength="100" rows="2" cols="45" placeholder="Заголовок"></textarea>
<textarea id="myDesc" maxlength="250" rows="4" cols="45" placeholder="Описание"></textarea>
<input id="myBtn" type="text" maxlength="25" placeholder="Кнопка">
<input id="picture" type="file" name="file1">
<button id="reset">Сбросить</button>
<button id="download">Скачать</button>
</div>
Вторая версия генератора

Ввод
Отказаться от кнопки «Просмотреть» мне помог здравый смысл и события input, которое реагирует на каждое изменение текста в поле ввода, и change, которое сработает при потере фокуса с поля:

$(document).ready(function() {
$("#myTitle, #myDesc, #myBtn").on("input", delayChange);
$("#myTitle, #myDesc, #myBtn").on("change", doChange);
});

Чтобы после каждой набранной буквы весь текст не отправлялся в попап, я добавил функцию delayChange(). Она ждёт одну секунду, если больше не было нажатий, и отправляет обработанный текст в попап. Если же вставлять в поле скопированный текст и переходить сразу на следующее, то сработает событие change. Здесь задержка без надобности и достаточно функции doChange().

function doChange(e) {
obj = e.target;
var inpID = $(obj).attr("id");
$("."+inpID).html(nl2br(obj.value));
}

var timeout = null;

function delayChange(e) {
clearTimeout(timeout);
timeout = setTimeout(function() {
doChange(e);
}, 1000);
}

Добавление иллюстраций
Чтобы добавить иллюстрации, я вставил стандартный инпут <input type="file">, но чтобы стилизовать внешний вид под себя — подключил библиотеку FileInput.

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

После выбора файла, также как и с вводом текста, надо подставить его в попап. По знакомому нам событию change вызывается функция previewFile().

$(document).ready(function() {
$("#picture").on("change", previewFile);
});

Она считывает файл методом readAsDataURL как кодированный url, чтобы в итоге изображение оказалось в попапе в обычном теге <img>.

function previewFile() {
var preview = document.querySelector("#mixpanel-notification-img");
var file = document.querySelector("input[type=file]").files[0];
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) { reader.readAsDataURL(file); }
}

Скачивание
Что представляет собой скачивание превью? Нужно текущее состояние блока попапа на html-странице превратить в растровое изображение и после скачать. Для этого решил использовать открытую библиотеку html2canvas. Она в общих чертах берёт содержимое указанного нами блока и отрисовывает, как графику, в элементе <canvas>.

$(document).ready(function() {
$("#download").on("click", screenshot);
});

function screenshot() {
var canvasPromise = html2canvas(document.getElementById("mixpanel-notification-mainbox"), {
useCORS: true
});
canvasPromise.then(function(canvas) {
saveAs(canvas.toDataURL("image/png"), "mixpanel-web.png");
});
}

Это только часть дела. Полученное в канвасе изображение нам ещё нужно скачать. Сразу после отрисовки вызывается функция saveAs(), которая создаёт временную ссылку для скачивания канваса и эмулирует клик по ней, подчищая всё за собой:

function saveAs(uri, filename) {
var link = document.createElement("a");
if (typeof link.download === 'string') {
link.href = uri;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
window.open(uri);
}
}

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

Работа второй версии генератора

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

Например, я делал страничку локально и c html2canvas не работало скачивание, пока в консоли Хрома не обнаружил ошибку. При запуске из папки не выполнялся метод toDataURL: Хром считал, что в канвас попадают данные с другого домена и нарушается Same Origin Policy. Стоило загрузить генератор на хостинг и всё сразу заработало.

Когда забыл про инструменты отладки в Хроме

Заключение

Знать хотя бы немного код — отличный мастхев для дизайнеров. Вы сможете лучше понимать разработчиков и верстальщиков. Вы сможете самостоятельно делать простые прототипы и автоматизировать собственную работу. Да и лишний навык — это +1 балл в резюме и лишний 0 к возможной зарплате.

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

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

Когда несколько строк кода немного улучшают жизнь , находишь в этом особое очарование. Если нравится это направление, то находишь время для практики, идёшь к поставленным целям и запускаешь свои проекты. Я по-прежнему не обладаю сильными знаниями в языках программирования, но мне нравится работать с кодом. И это главное.

Прим. автора: спасибо Коле Жидкову за терпеливый перебор CSS стилей попапа, Радмиру Кашаеву за ликбезы по кодингу и Тане Иншаковой за редактуру.

Где меня найти: Telegram / Facebook / Behance / Dribbble

--

--

Сергей Осокин
Дизайн-кабак

Пишу, когда не лень, о практичных вещах. Иллюстратор в Модульбанке.