Использование WebAssetsManager Joomla 4 и добавление собственных пресетов с помощью плагина | Веб-студия Nat.od.ua
Использование WebAssetsManager Joomla 4 и добавление собственных пресетов с помощью плагина
В мире фронтенда многие ресурсы (ассеты) связаны между собой. В Joomla никогда не было простого способа указать эту связь, но Joomla 4 изменила эту ситуацию, введя концепцию Web Assets. Управление JavaScript и CSS в Joomla значительно упростилось, благодаря классу WebAssetManager. Есть замечательная статья Как правильно подключать JavaScript и CSS в Joomla 4, в которой подробно и с примерами кода рассказывается об этой концепции и её применении. Рекомендую ознакомиться с ней для более полного понимания сути этой статьи.
Однако, в процессе разработки собственных решений я столкнулся с проблемой. Решение её в данной заметке будет небольшим дополнением к вышеупомянутой статье.
Задача
Задача заключается в том, чтобы подключить в общий реестр скриптов, стилей и пресетов js-библиотеку (в моём случае — Swiper.js) таким образом, чтобы она была доступна из самых разных мест Joomla 4 и её можно было использовать для разных расширений (возможно не только моих), автономно её обновлять.
Например: js-библиотеку подключает плагин, а использовать её может и модуль, и компонент, и контент-плагин, и плагин поля.
Образцом поведения является встроенный в Joomla 4 Bootstrap 5. Он поддерживает модульное подключение с автоматическим подключением всех зависимостей, которые описаны в файле media/vendor/joomla.asset.json.
Joomla 4 будет искать определение ассетов автоматически во время выполнения в следующем порядке:
А затем загрузит их в реестр известных JavaScript и CSS файлов.
Редактировать файлы ядра — нельзя (хотя, к сожалению, это распространено среди разработчиков, желающих быстро решить какую-нибудь задачу). Значит нам нужен плагин, которым можно «подлезть» на этапе формирования реестра ассетов и добавить в него нужные нам веб ассеты. Это решение было очевидно сразу.
Однако, все примеры создания и подключения скриптов, стилей и пресетов предполагали, что регистрируется и начинает использоваться ассет в одном и том же месте. Попытки вынести подключение ассета в плагин, а использовать ассет в модуле через $wa->usePreset, $wa->useScript приводили к ошибке «There is no «swiper-bundle» asset of a «script» type in the registry.»
Для того, чтобы разобраться в работе системы я начал анализировать код «коробочных» расширений.
Пример из системного плагина jooally — плагина версии для слабовидящих
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined(‘_JEXEC’) or die;
use JoomlaCMSApplicationCMSApplicationInterface;
use JoomlaCMSFactory;
use JoomlaCMSLanguageText;
use JoomlaCMSPluginCMSPlugin;
use JoomlaEventSubscriberInterface;
/**
* Jooa11y plugin to add an accessibility checker
*
* @since 4.1.0
*/
class PlgSystemJooa11y extends CMSPlugin implements SubscriberInterface
{
/**
* Application object.
*
* @var CMSApplicationInterface
* @since 4.1.0
*/
protected $app;
/**
* Affects constructor behavior. If true, language files will be loaded automatically.
*
* @var boolean
* @since 4.1.0
*/
protected $autoloadLanguage = true;
/**
* Subscribe to certain events
*
* @return string[] An array of event mappings
*
* @since 4.1.0
*
* @throws Exception
*/
public static function getSubscribedEvents(): array
{
$mapping = [];
// Срабатываем только на фронте
if (Factory::getApplication()->isClient(‘site’))
{
/**
* Срабатываем на событие onBeforeCompileHead и вызываем функцию initJooa11y.
* Можно по старинке упростить и использовать public function onBeforeCompileHead()
*/
$mapping = ‘initJooa11y’;
}
return $mapping;
}
}
Плагин срабатывает на событие onBeforeCompileHead. На этом событии возможно обработать всё, что составляет содержимое
страницы в Joomla 4: title, мета-теги и т.д.В самой функции initJooa11y идут проверки на CLI, REST API — чтобы плагин срабатывал только при выводе HTML. В самом конце функции происходит регистрация и добавление скриптов и стилей для функционирования версии для слабовидящих:
// Get the document object.
$document = $this->app->getDocument();
/** @var JoomlaCMSWebAssetWebAssetManager $wa*/
$wa = $document->getWebAssetManager();
$wa->getRegistry()->addRegistryFile(‘media/plg_system_jooa11y/joomla.asset.json’);
$wa->useScript(‘plg_system_jooa11y.jooa11y’)
->useStyle(‘plg_system_jooa11y.jooa11y’);
В файле media/plg_system_jooa11y/joomla.asset.json описываются файлы и их зависимости для работы плагина. Обратите внимание на то, что сразу после регистрации ассета начинается его использование — useScript и useStyle.
Но такое поведение меня не устраивало, так как хотелось достичь большей универсальности и автономности элементов. Помогли собственные поиски и отклик Joomla-сообщества. Итак….
Как добавить собственные js и css в Joomla 4 и сделать их доступными глобально?
Создаём плагин группы system. Официальная документация для разработчиков Joomla 4 по созданию плагинов. Можно по старинке использовать методы вида public function onBeforeCompileHead(). В таком случае плагин можно будет использовать как в Joomla 3, так и в Joomla 4. А можно использовать новый способ, предложенный в Joomla 4.1.
defined(‘_JEXEC’) or die;
use JoomlaCMSFactory;
use JoomlaCMSPluginCMSPlugin;
use JoomlaEventSubscriberInterface;
class PlgSystemWtjswiper extends CMSPlugin implements SubscriberInterface
{
/**
* Subscribe to certain events
*
* @return string[] An array of event mappings
*
* @since 4.1.0
*
* @throws Exception
*/
public static function getSubscribedEvents(): array
{
$mapping = [];
// Only trigger in frontend
if (Factory::getApplication()->isClient(‘site’))
{
$mapping = ‘addSwiperPreset’;
}
return $mapping;
}
}
Такой способ при правильном применении и вызове события позволяет не запоминать порядок передаваемых аргументов.
Самым важным оказалось найти правильное системное событие, на этапе которого есть возможность добавить свои веб-ассеты глобально в Joomla 4 Web Assets Manager. Таким событием оказалось onAfterInitialise. В моём случае попытки зарегистрировать веб-ассет на событии onBeforeCompileHead приводили к тому, что joomla.asset.json добавлялся в реестр ассетов, но не парсился. Что равносильно тому, что его не существует.
Следующий код позволяет зарегистрировать javascript-библиотеку
public function addSwiperPreset()
{
// Only trigger in frontend
if (Factory::getApplication()->isClient(‘site’))
{
/** @var JoomlaCMSWebAssetWebAssetManager $wa*/
$wa = Factory::getDocument()->getWebAssetManager();
$wa->getRegistry()->addRegistryFile(‘media/plg_system_wtjswiper/joomla.asset.json’);
return true;
}
}
Обратите внимание на метод addRegistryFile(), где указывается путь к файлу joomla.assets.json от корня сайта. Так же существует прокси-метод addExtensionRegistryFile(string $name), который принимает в качестве параметра системное имя расширения, по которому доступны его веб-ассеты в папке media: com_content, plg_system_jooally и т.д. Тогда подключаться будет файл ‘media/com_content/joomla.asset.json’ и ‘media/plg_system_jooally/joomla.asset.json’ соответственно.
Содержимое файла joomla.assets.json
{
«$schema»: «https://developer.joomla.org/schemas/json-schema/web_assets.json»,
«name»: «swiper»,
«version»: «8.2.4»,
«description»: «Swiper js library»,
«license»: «GPL-2.0-or-later»,
«assets»:
}
]
}
Uri в json в зависимости от типа ассета автоматически дополняется ‘js’ или ‘css’. Если вы подключаете файл media/plg_system_wtjswiper/css/swiper-bundle.min.css, то uri файла в joomla.assets.json будет plg_system_wtjswiper/swiper-bundle.min.css
Такой же принцип использовался раньше в Joomla 3 при подключении ресурсов с помощью HTMLHelper (ex. JHTML).
Так же полезные ресурсыРесурсы сообщества:Telegram:
Ошибки, которые совершают начинающие JS-разработчики / Хабр | Веб-студия Nat.od.ua
Ошибки, которые совершают начинающие JS-разработчики / Хабр
На первый взгляд, синтаксис JS прост и интуитивно понятен, что подкупает. Однако это не мешает тем, кто делает первые (или не первые) шаги в нём, допускать ошибки. Мы попытались осветить некоторые промахи начинающих разработчиков.
Язык JavaScript используется во фронтенд-разработке для браузерных приложений на стороне клиента. Для начала изучения достаточно простого редактора типа Notepad, браузера и какого-нибудь из многочисленных руководств для чайников. Но JavaScript проявляет себя не совсем так, как другие языки в разных ситуациях, и иногда это способствует возникновению ошибок. К примеру, нестрогая типизация языка и вольная трактовка данных может привести к тому, что данные будут интерпретироваться не так, как предполагает разработчик на этапе создания кода. Ошибки находятся в ходе работы этого кода.
Программист и преподаватель
Переменная не определена либо недоступна в текущей области кода
Такое происходит сплошь и рядом — обращение к переменной, которая ранее не была объявлена либо недоступна в текущей области кода. Например, код:
Без предварительного определения переменной x породит ошибку.
Uncaught ReferenceError: x is not defined
Кроме того, переменная должна быть видна в текущем контексте. Сравните два примера.
Код 1.
Код 2.
Код 1 на шестой строке выдаёт ошибку.
Uncaught ReferenceError: Cannot access ‘a’ before initialization
Дело в том, что переменная a определена внутри функции и недоступна за её пределами.
А код 2 без ошибок вернёт 5, потому что функция summa() имеет доступ ко всем переменным, определённым в глобальной области. Понимание области видимости важно в Javascript, области могут быть вложенными друг в друга, при этом дочерние области видимости будут иметь доступ к родительским, но не наоборот.
Неверно организовано условие сравнения if
Чтобы записать условие сравнения переменной с каким-либо значением, используется оператор ==.
Однако если ошибиться и использовать одинарный знак =, то вместо сравнения в круглых скобках окажется присваивание.
В JavaScript эта операция будет истинной, в то время как иные языки программирования могут среагировать ошибкой.
Подвид предыдущей ошибки — когда переменная сравнивается не просто со значением, а с конкретным — единицей.
Тут дьявол в деталях. По-булевски единица — это истина, а ноль — ложь. В результате выражение будет истинно.
Сравнение значений разных типов
Иной раз сравниваются переменные, которым были присвоены значения разных типов.
Ввожу 5 и 125, а мне в итоге пишут, что 5 больше 125, почему?
Отвечаем: в этом примере переменные x и y сравниваются как строки, а не как числа, так как после получения значений они так и остались строками.
Ситуация изменится, если приведём значения переменной к числу.
…
x = parseInt(x)
y = parseInt(y)
…
К слову, в коде полезен === . Это оператор строгого равенства, который проверяет сравнимое с учётом типов.
if(x === y) { … }
В этом фрагменте кода сравнение сразу вернёт ложь, если переменные разных типов.
Объявленные в цикле переменные не исчезают после его завершения
Следующий код нередко применяется в несложных сценариях, его любят начинающие разработчики.
Если попытаться использовать переменную i после выхода из цикла, то код в строке 4 приведёт к ошибке.
Переменная ликвидируется после окончания цикла, её значение будет не определено. В этом можно убедиться:
console.log(typeof i == typeof undefined) // выведет true
Попробуем при объявлении счётчика в цикле вместо let (это объявление переменной с блочной областью видимости) использовать директиву var.
Тогда i после выхода из цикла продолжит жить своей жизнью.
Некорректное использование this
Ошибка возникает, когда специальное ключевое слово this отсутствует в коде либо используется неправильно. Ключевое слово this ссылается на контекст выполняемой функции. Оно помогает работать с объектами. Но имеет значение контекст — какой именно объект в данный момент кода будет описан словом this.
В строке 5 переменная objProperty не определена, код вернёт ошибку.
Uncaught ReferenceError: objProperty is not defined
А всё потому, что пропущено ключевое слово this. Если внутри объекта myObject требуется обратиться к значению его свойства, то это делается следующим образом: this.objProperty.
Другой пример:
Ключевое слово this на строке 4 употребляется, однако код вернёт ошибку.
Uncaught TypeError: this.clearView is not a function
В этой строке контекст для this — уже область функции setTimeout (объект window).
Чтобы достичь нужного контекста, следует обратиться к нему, сделать это можно разными путями:
-
Совместимым со старыми браузерами способом — определить выше переменную и использовать в нужный момент именно её.
…
var self = this;
this.timer = setTimeout(function() {
self.clearView();
}, 100);
…
-
Использовать метод bind(), который работает не в совсем старых версиях браузеров.
Form.prototype.submit = function () {
this.clearLocalStorage();
this.timer = setTimeout(this.countTime.bind(this), 100);
};
Form.prototype.countTime = function(){
this.clearView();
};Использование alert
Это, скорее, не ошибка, а рекомендация более дружелюбного общения с посетителем. Чтобы мгновенно увидеть значение переменной value, можно просто взять и написать alert(value). Однако это не всегда поможет для решения сиюминутной проблемы. Например, если переменная value является объектом, то это мало что даст. Но существует набор решений для разных случаев.
Как правило, вывод данных нужен в ситуациях, когда хочется:
-
Что-то сказать посетителю, вывести информационное или предупредительное сообщение. Для этой цели применяют разные подходы с помощью jquery и bootstrap. К тому же в некоторых браузерах вывод данных с помощью alert блокирует экран и не даёт ничего сделать на странице, пока этот алерт не отожмёшь.
-
Произвести отладку в ходе разработки. В этом случае можно использовать объект браузера Console. Например, console.log(value) выведет сообщение в веб-консоль.
Это лучше alert. Во-первых, как следует из названия, служебные данные выводятся в консоли. Туда заходит немного рядовых посетителей, и если вы вдруг забыли убрать отладочный вывод, его увидят далеко не все. Во-вторых, с помощью отладки в консоли можно детально смотреть на объекты, о чём вскользь упоминалось выше.
Зададим объект и посмотрим на него разными способами.
Результат кода alert(Person).
И результат вывода в консоль. Как видите, более информативно.
Неверное подключение библиотек
Такое происходит, когда библиотеку:
-
не подключили,
-
не подключили вовремя, а библиотека или скрипт, которые в ней нуждаются, уже подключены/запущены.
И вместо галереи или слайдера поджидает ошибка.
Uncaught TypeError: Cannot read properties of undefined
Смотрим код.
Item 1
Item 2
Item N
Библиотека Owl Carousel имеет в зависимостях Jquery, но подключается раньше.
В примере выше ошибку генерирует скрипт инициализации карусели.
Uncaught TypeError: owl.owlCarousel is not a function
У библиотеки не было шанса объявиться. Как правило, когда на странице используется ряд скриптов, ошибки плодятся как снежный ком.
Следует поменять местами подключения Jquery и Owl Carousel — строки 3 и 4.
Выводы
Избежать распространённых ошибок помогут практика и понимание того, как работает язык. Отследить баги помогут такие инструменты, как JSHint, JSLint, ESLint.
Кроме того, в IDE обычно имеются плагины для дебаггинга. В начале статьи мы говорили о том, что начинать изучение JavaScript можно с помощью редакторов типа Notepad. Но в удобной настроенной среде это делать гораздо приятнее и эффективнее.
Как вы слышали не раз, не ошибается тот, кто ничего не делает. Красное оповещение об ошибке в консоли не должно пугать. Это подсказка, что пошло не так, инструкция к действию — погуглить фразу Javascript <текст ошибки>.
Возрождение простых сайтов. Статика, 0kB JS, ничего лишнего | Веб-студия Nat.od.ua
Возрождение простых сайтов. Статика, 0kB JS, ничего лишнего
Как мы обсуждали в прошлый раз, удручающее ожирение сайтов и софта вернуло моду на простые, маленькие проекты. И сейчас происходит своеобразный ренессанс веба 90-х, вплоть до стиля Geocities (такой был бесплатный хостинг) и веб-страниц в виде PDF. Таковы примеры самореализации. У каждого человека — уникальный сайт, который отличается от остальных и отражает его личность.
Статический сайт можно выполнить в одном файле HTML, а динамический — в одном бинарнике (под катом). Тенденция видна везде. Современные фреймворки даже хвалятся «0кБ JavaScript» по дефолту, а браузеры внедрили технические усовершенствования, которые во многом аннулируют преимущества использования SPA.
Читать дальше →
Разработал генератор резюме с фишками для разработчиков / Хабр | Веб-студия Nat.od.ua
Разработал генератор резюме с фишками для разработчиков / Хабр
Раньше я отправлял много резюме и подавал заявки на различные доски объявлений, и я всегда хотел иметь резюме, которое будет соответствовать всем таким доскам объявлений с функцией автоматического импорта (где поля сами автозаполняются исходя из данных в резюме PDF), и не хотел видеть бренды/логотипы генераторов резюме в своем резюме, просто Plain Text — только информацию обо мне, а также некоторые дополнительные функции.
На самом деле с такой проблемой сталкивались и мои близкие и знакомые мои люди, в том числе коллеги.
Я разрабатывал данный проект в одиночку в течении года, можно сказать one-man стартап. Я обращался только к графическому дизайнеру для подбора цветов и отрисовки логотипа и другой графики на сайте.
Описание проекта
Стэк: Django, Bootstrap
На сайте представлены бесплатный и платный тарифы $3/мес.
На бесплатном можно смело создавать любое количество резюме для себя и ваших близких, искусственных ограничений на количество нет, а также, загружать фотографию в резюме, и это всё экспортировать в PDF.
На платном тарифе появляются дополнительные возможности, такие как:
-
Изменение режима приватности страницы с резюме
-
Добавление статистики Stackoverflow
-
Отображение списка репозиториев Github
В данный момент шлюзом оплаты является Paddle и скорее всего карты Российских банков не будут приняты к оплате. Если вам очень понравился сайт и вы считаете его полезным и вы из России, то напишите мне, мы что-нибудь придумаем.
Для тех, у кого имеется карта иностранного банка, предлагаю воспользоваться промокодом ilovegeekcv , который дает 50% скидку на оплату подписки.
Также, утром я опубликовал проект на ProductHunt , и если вам понравился данный сервис или вы просто хотите поддержать мои начинания, пожалуйста, поставьте Upvote.
Сам сайт, минуя ProductHunt: https://geekcv.io
7 советов в помощь дизайнеру интерфейсов / Хабр | Веб-студия Nat.od.ua
7 советов в помощь дизайнеру интерфейсов / Хабр
Cпасибо, за вашу огромную активность под прошлой статьей, ведь именно это вдохновляет меня собирать всю волю в кулак и попытаться поделиться чем-то полезным с вами.
1 Тип. Помоги пользователю сделать выбор
Когда у нас стоит важнейший (так определенно кажется пользователю в данный момент) выбор между вариантами подписки на сервис, комплектации гаджета, или может быть даже вариантов туров на Байкал, пользователя в прямом (так представляю я) смысле настигает паралич. Как известно, чем больше выбора, тем дольше принимается решение о покупке, а порой и вовсе отказ от целевого действия на время, или навсегда.
Чтобы побороть паралич выбора и подтолкнуть людей принять решение, подчеркивай и выделяй более выгодные параметры из множества. Обозначь товар, который будет доминировать среди других представленных. Так же этот эффект в законах UX известен под названием – Эффект Изоляции.
1. Помощь в выборе2 Тип. Призыв к действию
Правильно используй и располагай кнопку СТА. Частая ошибка при разработке интерфейса, это создание важных кнопок СТА, которые сливаются с общим контентом, или вовсе теряются на фоне яркого и перегруженного бэкграунда. Будь внимателен проектируя свой интерфейс: отделяй кнопки, используй исключающий цвет, чтобы он выделялся на фоне остального контента.
Используя тон ты можешь сделать некоторые элементы темнее по отношению к твоей кнопке. Исходя из правил твоего UI примени тень, так чтобы кнопка казалась ближе. Не забывай про интерактивный дизайн и добавь в свою библиотеку компонентов эффекты наведения и нажатия для кнопки, а так же не забудь поделиться ей с командой.
2. Призыв к действию
3 Тип. Вовлечение в продукт
На первом этапе знакомства с продуктом, вместо того чтобы просить пользователя пройти немедленную регистрацию, попробуй продемонстрировать продукт в действии. Например: при регистрации в языковом приложении, вместо того, чтобы сразу пройти регистрационный путь, тебе предлагается пройти несколько несложных заданий, узнать свой уровень или посмотреть примеры квестов.
Чтобы продемонстрировать преимущества продукта, используй постепенное вовлечение. Пользователи, которые смогут увидеть ценность продукта, начнут понимать, чем он может быть полезен для них, и будут максимально открыты. Отсрочив процесс регистрации, дай клиенту настраивать и использовать твой продукт.
3. Вовлечение в продукт
4 Тип. Безопасность и надежность
Когда пользователь заключает сделку и начинает работать с приватными для него данными, например ввод банковской карты, твоя задача убедить его, что все шикарно. Попробуй добавить гарантию, расскажи про безопасность, покажи выгодные стороны сервиса, такие как: бесплатная доставка или возможность отказа от покупки в любой момент. Не дай клиенту поводов для беспокойства!
4. Безопасность и надежность5 Тип. Наборы коллекций
Дисклеймер: собирательство это ужасная штука, и скорее отдельная тема для разговора. Мы мотивированы собирать вещи. Виртуальные или физические – это неважно. Собирание вещей устанавливает цель к которой нужно стремиться (да да), а получение полного набора мотивирует больше чем что-либо, предоставляя преимущества.
Например, приложение Дуолинго отлично демонстрирует как они используют, этот прием устраивая ежемесячный марафон, участвуя в котором, ты зарабатываешь медали или достижения. Еще один пример это ВкусВилл. Они добавили раздел достижения, и теперь, приобретая нужное количество продуктов или делая онлайн заказы, ты зарабатываешь ачивку. В некоторых сервисах по аренде авто, ты так же можешь заметить такую тенденцию.
5. Пример продуктов
Демонстрация собранных предметов подкрепляет поведение, показывая прошлые действия как достижения. В целом ты можешь усилить мотивацию сбора полного набора, если возьмешь на себя всю нагрузку.
Процесс сбора продуктовой корзины демонстрирует, что тебе не хватает 2х ингредиентов. А уж если ты их соберешь, то точно сможешь приготовить потрясающий торт.
5. Наборы коллекций6 Тип. Цена и комиссия
Покажи пользователям четкую цену продукта, доставки или комиссии. Никогда не скрывай от пользователей конечной стоимости, это вызовет недоверие к твоему продукту. Также на моменте чекаута не стоит добавлять неожиданные комиссионные сборы или сборы для доставки. Укажи стоимость. Когда пользователь находится в корзине, он должен четко и точно найти информацию о стоимости услуги. Если мы не говорим про рынок элитных или редких вещей, стоимость которых оговаривается по индивидуальному подходу и совокупности множества факторов. Ну или мы просто разводилы, которым нужно лить трафик без разборно, чтобы наседать на бедного пользователя.
6. Цена и комиссия7 Тип. Ускорьте загрузку
Ускорение загрузки, это отличный способ не заставлять людей ждать. Время определенно влияет на конверсию. Разговор здесь не только за техническую часть: код и его оптимизация. Конечно речь так же идет и про визуал. Применяя психологические эффекты, к которым ты добавишь готовых шаблонов – пользователь точно оценит ценность продукта, и сможет занять себя в момент загрузки контента.
7. Загрузка продукта
Правила которыми, пользуются дизайнеры, обязательно должны быть подкреплены исследованиями, и конечно же соответствовать требованию бизнес-заказчика. Бывает так, что дизайнеры нарочно игнорируют правила юзабилити для того, чтобы иметь выгоду с определенных действий. Например: кнопка отписаться от подписки в гаджетах apple.
Самое главное это то, чтобы твой дизайн был дружелюбным и привлекательным. Никогда не идите на поводу у заказчиков, и старайтесь отстаивать свое мнение, потому что именно от нас зависит как работает и как выглядят наши интерфейсы. Дизайн решает проблемы, с которыми сталкивается пользователь, а не создает их…
Чек-лист по проектированию регистрации / Хабр | Веб-студия Nat.od.ua
Чек-лист по проектированию регистрации / Хабр
В проектировании сложно давать универсальные советы. Сколько задач, контекстов и целевых аудиторий — столько и решений. Поэтому вместо чек-листа с рекомендациями предлагаю вашему вниманию чек-лист с вопросами. Сегодня на повестке вопросы, которыми я задаюсь при проектировании форм регистрации пользователей (которые сами по себе могут оказаться вершинами айсберга). Для новичков контент полезный. Для продвинутых — интересный (проверьте, сколько пунктов учитываете в работе вы сами). А для профессионалов — повод показать автору, что он упустил что-то важное, и утереть ему нос. Поехали.
-
Нужна ли она (регистрация)? Можно ли воспользоваться функциями сервиса без регистрации? Какой она будет?
-
Предварительная регистрация. Всё закрыто до создания аккаунта
-
«На лету». В процессе использования сервиса. Многие функции доступны без регистрации
-
«Манипулятивная». Пользователю дают создать в сервисе какую-либо ценность своими руками, после чего просят зарегистрироваться, чтобы получить доступ к этой ценности
-
-
Будет ли регистрация отличаться для разных языков или регионов?
-
Будет ли регистрация отличаться для разных пользовательских ролей?
-
Нужна ли для регистрации страница с отдельным адресом или всё будет происходить в модальных окнах?
-
Каким способом регистрируем пользователя?
-
Закрытая по приглашениям
-
С помощью адреса электронной почты
-
По номеру телефона
-
Через соцсети
-
Какие конкретно? Нужно ли показывать разные для разных регионов и языков? Не забыли ли добавить примечание, что при такой регистрации пользователь всё равно соглашается с определёнными документами?
-
-
С помощью логина в свободной форме
-
Руками администратора через админку
-
-
Будет ли необходимость в двухфакторной защите? Будет ли она опциональной? Какого толка?
-
Какие данные собираем? Зачем? Как проверяем эти данные на достоверность? Как помогаем пользователю ввести данные правильно с первого раза?
-
Что делаем в сценариях, когда пользователь всё-таки ввёл свои данные неверно (например, ввёл адрес электронной почты с опечаткой или вообще чужой)?
-
Какие данные собираем в момент регистрации, а какие позже? На что это может повлиять?
-
-
Не забыли ли о данных для маркетологов?
-
UTM, способ регистрации, дата и время, был ли аккаунт уже зарегистрирован до этого, какой язык интерфейса у пользователя, согласился ли он на рассылку, в какую группу рассылки попал?
-
-
С какими документами пользователь должен согласиться? Как с ними можно ознакомиться? На каких они языках? Нужен ли контроль того, что пользователь действительно ознакомился с документами? Можно ли ставить галочку за пользователя? Обезличенная ли формулировка в этих соглашениях? Должен ли пользователь отдельно соглашаться на подписку на рассылку? Какая это будет конкретно рассылка? На каком языке и как его определить? Как от неё отписаться?
-
Нужна ли защита от ботов? Какая? Смогут ли ей воспользоваться люди с ограниченными возможностями?
-
Какие могут возникнуть ошибки? Где и как о них сообщать?
-
Нужна ли верификация аккаунта при регистрации? Как она будет организована? Будут ли набор функций в системе отличаться для верифицированных и неверифицированных пользователей?
-
Виды верификаций: автоматические, полуавтоматические, вручную. По емейлу, по открытым юридическим данным, по скану документов, по тестовому платежу и т.д.
-
-
Помешает ли регистрация целевому действию? Не окажется ли пользователь далеко от своей цели после всех процедур? Нужно ли ему авторизоваться после регистрации или это произойдёт автоматически?
-
В случае сложной формы регистрации может ли пользователю понадобиться помощь оператора?
-
Какое письмо получит пользователь после регистрации? Какое там будет послание? Какое целевое действие? Будет ли там сообщение для тех, кто получил его по ошибке?
-
Сможет ли пользователь зарегистрироваться, если он удалял свой аккаунт в прошлом? Будут ли при этом какие-то особенности? Например, будет ли ему снова доступен триал? Какая информация в его личном кабинете будет восстановлена? Насколько это законно?
-
Сможет ли пользователь зарегистрироваться, если его аккаунт был забанен и он его удалил?
Вот и весь чек-лист! Он у меня есть в гугл.доке, если вам так будет удобнее. У меня в Проекторате был выставлен на продажу видеокурс по этому чек-листу. Я там каждый пункт разжёвывал и показывал живые примеры. Но спроса на него не было, поэтому я снял его с продажи, равно как и все остальные свои видеокурсы. Можете смотреть бесплатно, вот он:
Если захотите меня отблагодарить, то достаточно будет подписаться на паблик Проектората Вконтакте или канал в Телеграме. Возможно, скоро буду делать набор в четвёртый поток курса по проектированию интерфейсов (как писать функциональные требования, как делать интерактивные прототипы, как описывать их в функциональных спецификациях, вот это всё). А может и не буду. От спроса будет зависеть. Сейчас эти курсов — как грязи. Если заинтересуетесь, — стучитесь в личку. Не уверен, что дал в этой статье достаточно пользы, чтобы претендовать на рекламу.
Если не нашли в чек-листе чего-то важного — пишите об этом в комментах. Добавим в доку, принесём ещё больше пользы.
Анимация аккордеона и свойства height (max-height) в чистом CSS / Хабр | Веб-студия Nat.od.ua
Анимация аккордеона и свойства height (max-height) в чистом CSS / Хабр
Всем привет, мне пришлось очень долго промучаться с анимацией Аккордеона и свойства max-height не прибегая к помощи Js в вычислениях, и сейчас я поделюсь с вами оптимальным решением.
P.S.: Java-sctipt использовался только для воздействия на класс (смены класса) , что можно сделать и с помощью псевдо классов css, например: Active.
Код JS
Было перепробовано несколько вариантов с использованием отрицательного margin-top, position: absolute и transform: translate. Но во всех вариантах, обязательно, что бы контент не было видно за рамками родительского блока, добавьте его контейнеру свойство oveflow:hidden.
Код CssКод Html
Итак, Margin-top недостаточно надежен т.к берет процентный отступ, от ширины родителя, а не его высоты. Заказчик рано или поздно может захотеть изменить блок, и в лучшем случае список будет просто быстрее заезжать наверх, из-за увеличения ширины блока, и соответственно отступа наверх, а в худшем не будет скрываться полностью, если высота станет слишком большой, а ширина не изменится.
Transform: translate;, адаптивен и плавно анимируется, но оставляет под собой пространство. Если добавить к этому свойству position: absolute с задержкой (transition: transform 1s, position 1s 1s), то пустое пространство исчезнет, но мгновенно, сразу после конца анимации, т.к position не анимируется. Это создаст неприятное ощущение рванной анимации.
Transform: translate без position absolute
Transform: translate c position: absolute через задержку
Оптимальным вариантом будет свойство max-height, оно куда надежнее фиксированной высоты, и может подстраиваться под меньшее количество контента. Но и оно отказывалось работать до последнего, т.к я указывал начальное значение в процентах или оставлял max-height: auto — анимация не работала. Как оказалось при указании высоты в пикселях, все начинает работать. Значение в пикселях следует указывать с запасом как минимум в 2 раза, что добавит надежности вёстке, так как если заказчик захочет изменить сайт и добавит контента в блок, что увеличит его высоту, у нас еще будет запас по max-height. Единственное, что вам стоит уяснить, анимируется не текущее значение высоты блока, а разность высот между max-height в начале и после анимации. В моем случае значение max-height — 3000px, а высота контента примерно 550px. Таким образом, при сворачивании этого списка анимация начнется с задержкой, а именно, тогда когда анимация дойдет до значения высоты блока (в моем случае около 550px), т.к как сначала max-height снизится до этого числа, но блок не измениться, ведь его высота меньше max-height, а уже затем когда высота max-height, станет меньше высоты блока, блок начнет уменьшаться. При разворачивании max-height растет от нуля и изменения видны мгновенно.
До аннимацииПосле аннимации
Я надеюсь, что мне удалось вам помочь!
Если у вас остались вопросы, критика или комментарии — обязательно напишите мне, я с радостью отвечу вам.
А сейчас я прощаюсь и желаю вам хорошего дня!
Денис
Как и зачем я отключил свой фавикон / Хабр | Веб-студия Nat.od.ua
Как и зачем я отключил свой фавикон / Хабр
Перевод статьи «Disabling My Favicon: How and Why»
Привет Хабр! Недавно в недельной подборке я увидел эту статейку на английском языке и решил ее перевести так как она показалась мне довольно интересной. Далее перевод.
И так начнем: на моем сайте нет фавикона, и, скорее всего, его никогда не будет.
Нельзя с полной уверенностью сказать, почему я пришел к такому решению, но, учитывая тот момент, что у меня нет логотипа — и я действительно не хочу его иметь — то и создание значка для сайта мне показалось излишним.
Но есть проблемка, фавикон нельзя просто не задать, поскольку большинство веб-браузеров все равно попытаются его запросить. А это в свою очередь означает, что при каждой загрузке страницы будет повторный запрос файла favicon.ico, который определится как Not Found.
Не знаю как вас, а меня это раздражает.
И так, что же нам делать?
Самый простой способ решить эту проблему это сделать прозрачную фавиконку, но это не решает мою проблему так как я хочу избавиться от лишнего запроса а не просто получить успешный ответ при запросе.
Попытка первая
Хотя пропуск тега icon и не приводит к желаемому результату, я решил поэкспериментировать со значениями, которые он дает. Моей первой попыткой было использовать простой хэш:
В целом, хоть это и помогло устранить ответ 404 Not Found в запросе, но затем я столкнулся с другой проблемой — повторно запрошена вся страница. Это объясняется тем, что # в конечном итоге интерпретируется браузером как https://flower.codes/#, как практически и любой другой символ, с которым вы, возможно, захотите поэкспериментировать (пробелы, вопросительные знаки и т. д.).
Итог этого решения: не подходит.
Попытка вторая
И так, мы не можем просто пропустить фавикон и не можем использовать произвольный символ… Что же тогда делать?
Немного покопавшись, я наткнулся на концепцию, с которой большинство веб-разработчиков довольно хорошо знакомы: Data URLs.
Для непосвященных: URI данных позволяют встраивать файлы непосредственно в HTML, а не выполнять внешний запрос. Если максимально упростить, они обычно состоят из определения типа загружаемого файла (например, text/html или text/plain) и содержимого файла.
Это означает, что вместо загрузки внешнего файла вы можете включить его в строку следующим образом:
data:text/html,
Однако для наших целей мы можем определить Data URL, который фактически является пустым, просто опустив как тип контента, так и само содержимое:
Итог этого решения: подходит.
Хорошо, но… Зачем?
Как и ожидалось, это решило мою проблему. Включив содержимое напрямую и оставив его пустым, мы можем устранить повторный запрос, не вызывая никаких ошибок в консоли.
Но зачем мне все эти проблемы?
Хотите верьте, хотите нет, но мне на самом деле нравятся фавиконки. Я думаю, что они значительно упрощают организацию вкладок и закладок. Но во всемирной паутине, плотно заполненной ими, отказ от одного на моем собственном сайте казался маленьким способом выделиться (а пройти лишнюю милю, чтобы сделать это «правильным» способом – это просто вишенка на торте).
Если вдруг кому интересно то я веду телеграм канал по фронтенду где выкладываю интересные статьи на разные темы а так же сам периодически пишу шорт-риды которые могут быть вам полезны.
6 простых правил хорошего alt-текста / Хабр | Веб-студия Nat.od.ua
6 простых правил хорошего alt-текста / Хабр
Давайте поговорим о том, как написать хорошее описание фотографий в атрибуте alt.
В первой части мы обсудили основные правила написания alt-текста для фотографий и изображений. В этот раз поговорим о том, каким именно должно быть описание, чтобы в нём был смысл.
Альтернативный текст — это описание изображения словами. Это описание должно помогать людям, которые читают или слышат это описание, иначе оно не нужно и лучше вообще его не указывать.
Просто перескажите, что находится на картинке
Есть простой совет, чтобы создать идеальное описание.
Представьте, как вы звоните другу и рассказываете, что видите на изображении.
Но не переусердствуйте, так как лучше, если описание будет лаконичным.
Разноцветный кот есть корм и облизывается (https://unsplash.com/photos/_FlMYRBExBk)
Имя создателя и ключевые слова для поисковой оптимизации не должны находиться в описании изображения, но они могут находиться в статье.
Используйте контекст, в котором находится картинка
Одна и та же картинка может иметь разное описание в alt в зависимости от контекста. Контекст — это то, что окружает иллюстрацию, например, текст статьи, если картинка туда встроена.
Проще говоря,
Описание зависит от того, на чём сейчас нужно сфокусировать пользователя.
Посмотрите на картинку ниже и подумайте, какое описание вы бы указали в alt.
Есть несколько правильных ответов:
CSS is awesome.
Подойдет для статьи о том, как работает CSS (плохо).
Белая кружка с надписью.
Если ваша статья про кружки и никак не связана с веб-разработкой.
Бардак на столе разработчика: кружки, переплетенные провода, карточки.
Если рассказываете про жизнь во время пандемии или регулярную уборку на рабочем столе.
Белый стол.
Если продаёте столы и считаете, что то, что находится на столе, не имеет никакой разницы. Да хоть тарелка.
Белая кружка с надписью в квадрате «CSS is awesome» стоит на белом столе. Awesome выходит за пределы квадрата.
Этот вариант подойдет, если вы не понимаете контекста статьи, но нужно поставить какую-то картинку и что-то там написать. Так тоже можно делать.
Главная мысль в этих примерах такая, что вам нужно акцентировать внимание на том, что сейчас более важно для статьи в этом изображении. Чтобы определить «сейчас», нужно понимать, о чём написано в статье рядом с этим изображением. Если в статье рассказывается о том, какие виды кружек бывают, то нужно описать детали кружки на изображении, например «Белая кружка с надписью «CSS is Awesome»». Всё, что есть на фоне, в этом случае не важно.
Не пишите alt, если картинка не несёт смысла
Нет ничего плохого в пустом alt, если изображение не несёт дополнительного смысла. Например, как описать мою аватарку в интерфейсе сайта?
Для контекста: на аватарке нарисована голова человека, которые лежит на кровати и не может уснуть от копошащихся мыслей.
![]()
«Николай Шабалин» совсем плохой вариант, так как он полностью дублирует текст справа. Аватарка используется в шапке сайта, поэтому описывать её нет смысла.
Не описывать картинку нормально, но будьте аккуратнее и всегда помните про контекст.
![]()
Передавайте эмоции через alt
С первого взгляда не очевидно, что любая аватарка может передавать какие-то там эмоции, но в контексте иногда есть смысл их передать. Например, если бы статья была про бессонницу, то моей аватарке можно было бы написать alt «человек с кучей мыслей прям перед сном».
Радостный человек лежит в гамаке на закате (https://unsplash.com/photos/Kc4MGyzfOTI)
Эту картинку можно описать «Радостный человек лежит в гамаке на закате». Нужно ли писать здесь, что человек радостный, хотя мы даже не видим его лица? Это не обязательно, но можно так написать, если мы продаём гамаки, хотим дополнить картинку и сказать, насколько хорошо он себя чувствует в нашем удобном гамаке, лёжа в нём на берегу океана.
Про эмоциональное описание для изображений вы можете подробнее узнать в блоге Лео́ни Уотсон.
Не заигрывайте с декором ради декора
Все мы знаем, что декоративные изображения обычно используются без описания, хотя такая возможность есть. Для этого можно использовать свойства content: «» или, если вы используете изображение в content: url(), то правильно будет написать так:
content: url(«path/to/image.jpg» / «Описание декоративного изображения»).
Но лучше использовать этот способ пореже, так как чаще всего декоративные изображения бессмысленны. Но если по какой-то причине вам хочется передать эмоции декоративного изображения, то такая возможность есть.
Не пишите в alt названия файлов или имя фотографа
Я часто смотрю, какое описание заполняют в атрибуте alt, и удивляюсь, насколько фантазия может пойти не туда. Часть заполненный альтернативный текст полностью бесполезен, так как не передаёт смысла изображения.
Какое описание не подойдёт:
-
imgX2 или 7e0273c07fef3b598590d3fdddf7808604f0a191435c2c0c — это просто название или хэш файла с картинкой.
-
название сайта или название статьи — возможно, это проделки для SEO.
-
имя фотографа — тут всё понятно.
Все эти варианты никак не помогут в основной задаче альт-текста — понять, что было на картинке, которая не загрузилась, или при чтении страницы скринридером.
Итого — как написать хороший alt-текст
Просто понятное описание — самое хорошее решение, если оно не слишком длинное. Отсутствие описания — нормально, но должно быть к месту. Эмоциональное описание — тоже хорошо, если вписано в контекст.
А вот шесть правил коротко:
-
Просто расскажите, что видите на картинке — чем короче, тем лучше.
-
Используйте контекст, в котором находится картинка — то есть учитывайте, что находится вокруг неё на сайте.
-
Не пишите alt, если картинка не несёт отдельного смысла — например, аватарка в профиле.
-
Не стесняйтесь передавать эмоции через alt — если кто-то радуется или грустит, напишите об этом, если уместно.
-
Не пишите alt у декоративных изображений — например, у иконок.
-
Не пишите в alt название файла или имя фотографа — alt нужен не для этого.
Экспериментируйте, пробуйте и не бойтесь ошибиться.
способы сделать сайт послушным / Хабр | Веб-студия Nat.od.ua
способы сделать сайт послушным / Хабр
Вёрстка помогает нам выстраивать содержимое веб-страниц по определённым правилам: например, строго в соответствии с согласованным макетом или в зависимости от пользовательского устройства. Сегодня сайты неплохо умеют подстраивать свой контент и под различные размеры экранов, но так было не всегда.
Существует несколько основных подходов к вёрстке, особенности которых мы рассмотрим в этой статье на простом наглядном примере:
Структура представленной разметки страницы очень простая: сверху располагается шапка, ниже — основное содержимое страницы, которое включает в себя контейнер для карточек и сами карточки.
Для демонстрации подходов к вёрстке мы будем вносить изменения только в CSS, в то время как представленная выше HTML-разметка будет оставаться неизменной.
А теперь давайте вернёмся к обсуждению самих подходов.
Фиксированная вёрстка
Самым простым и не требующим больших усилий решением можно считать фиксированную вёрстку. Фиксированной она называется потому, что содержимое страницы, свёрстанной таким образом, никак не подстраивается под размер экрана и отображается на всех устройствах одинаково.
Для фиксированной вёрстки ширина контейнера, в котором находится весь контент, указывается в абсолютных величинах (например, px). Помимо ширины контейнера не лишним будет указать внешние отступы, чтобы контент отображался всегда по центру экрана.
Стили, указанные после отступа, нужны для формирования сетки контента, которая будет иметь три колонки одинаковой ширины и отступы в 24px между колонками и строками. Сетка задаётся с помощью CSS Grid Layout, и если вы ещё не знакомы с возможностями этого способа раскладки, рекомендую ознакомиться с данной статьёй.
.container {
width: 900px;
margin: 24px auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
Этого уже будет достаточно, чтобы добиться ожидаемого отображения веб-сайта на обычном экране компьютера.
Однако, такая вёрстка совершенно не подходит для отображения на мобильных устройствах: из-за фиксированной ширины контейнера пользователю придётся приближать страницу и скроллить её влево-вправо, чтобы иметь возможность прочитать имеющийся на ней текст.
Отзывчивая вёрстка
В таком случае мы могли бы сделать наш интерфейс чуть более дружелюбным, если бы стали использовать отзывчивую (или резиновую) вёрстку. Её особенность состоит в том, что для задания параметров используются не абсолютные, а относительные величины (например, %), благодаря чему содержимое страницы может подстраиваться под ширину экрана.
Для нашего примера также необходимо указать максимальную ширину контейнера, чтобы на больших экранах контент отображался точно так же, как и в случае с фиксированной вёрсткой.
Ещё мы добавим внутренний отступ, чтобы на маленьком экране карточки не прилипали к его краям. Именно из-за этих внутренних отступов в 16px слева и справа ограничения по максимальной ширине увеличиваются с 900px до 932px.
.container {
width: 100%;
max-width: 932px;
padding: 0 16px;
margin: 24px auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
Вот как поведёт себя резиновая вёрстка на средних и маленьких экранах. На планшете она отображается так же хорошо, как и на экране компьютера, но на мобильных устройствах ситуация только ухудшилась: карточки стали настолько узкими, что прочитать текст на них практически невозможно.
Адаптивная вёрстка
С ростом популярности смартфонов появилась и стала распространённой адаптивная вёрстка, которая позволила изменять стили контейнера в зависимости от ширины экрана. Этот подход может помочь нам избежать проблем, с которыми мы столкнулись выше, когда использовали резиновую вёрстку на маленьком экране.
С помощью медиа-запросов мы можем изменять сетку, по которой будет выстраиваться контент. Изначально стили указываются для минимальных размеров экрана (такой подход называется mobile-first), и если ширина экрана достигает какого-либо брейкпоинта, первоначальные стили заменяются новыми. Существует множество систем величин брейкпоинтов, но мы воспользуемся значениями, представленными здесь.
В нашем примере мы будем изменять максимальную ширину контейнера и сетку для расположения карточек: на маленьких экранах (шириной меньше 480px) колонка будет одна, на экранах средней величины (от 480px до 768px) — две, а на больших (шириной больше 768px) — три. Максимально возможная ширина контейнера по-прежнему 932px, она будет установлена на экранах, ширина которых равна этому значению или больше него.
.container {
max-width: 300px;
padding: 0 16px;
margin: 24px auto;
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 24px;
}
@media screen and (min-width: 480px) {
.container {
max-width: 480px;
grid-template-columns: repeat(2, 1fr);
}
}
@media screen and (min-width: 768px) {
.container {
max-width: 768px;
grid-template-columns: repeat(3, 1fr);
}
}
@media screen and (min-width: 932px) {
.container {
max-width: 932px;
}
}Отзывчиво-адаптивная вёрстка
Последним и самым современным подходом к вёрстке веб-сайтов является отзывчиво-адаптивная вёрстка, которая сочетает в себе положительные свойства двух рассмотренных выше подходов. Такая вёрстка подойдёт в том случае, когда приоритетная задача состоит в том, чтобы занять максимум от имеющегося пространства: например, если контент представлен не карточками, а изображениями, и нам не нужны поля слева и справа от контейнера.
При таком подходе вёрстка между брейкпоинтами ведёт себя абсолютно «резиново», но на брейкпоинтах могут меняться какие-то важные свойства отображения (в нашем случае — свойства сетки). Используя данный подход, вы можете быть уверены, что на экране абсолютно любого размера ваше приложение будет отображаться как нужно и им будет удобно пользоваться.
.container {
width: 100%;
max-width: 932px;
padding: 0 16px;
margin: 24px auto;
display: grid;
grid-template-columns: repeat(1, 1fr);
gap: 24px;
}
@media screen and (min-width: 480px) {
.container {
grid-template-columns: repeat(2, 1fr);
}
}
@media screen and (min-width: 768px) {
.container {
grid-template-columns: repeat(3, 1fr);
}
}
Последний рассмотренный подход к вёрстке считается самым надёжным и безопасным решением, однако, выбор типа вёрстки должен производиться индивидуально в зависимости от задач и структуры конкретного веб-приложения.
Код всех рассмотренных примеров вы можете посмотреть в песочнице.
В этой статье мы рассмотрели типы вёрстки, отличающиеся поведением на экранах разных размеров, но это лишь один взгляд на вёрстку. Существуют также иные подходы к выделению её типов, например, в зависимости от используемых HTML-тегов, но об этом мы поговорим уже в следующих статьях.












