Русский
Русский
English
Статистика
Реклама

Web-разработка

Перевод Восемь забавных вещей, которые могут с вами произойти, если у вас нет защиты от CSRF-атак

12.04.2021 18:13:34 | Автор: admin

Восемь забавных вещей, которые могут с вами произойти, если у вас нет защиты от CSRF-атак



Введение


В качестве программистов Typeable мы видим свою основную цель в том, чтобы приносить пользу нашим заказчикам. Однако я только что потратил некоторое количество денег заказчика и целый день на то, чтобы добавить защиту от подделки межсайтовых запросов (CSRF) на нашу страницу авторизации и, надеюсь, сделал это без каких-либо видимых следов. Ценность таких действий по обеспечению безопасности бывает трудно увидеть, поэтому я подумал, что полезно было бы описать, что именно может произойти без защиты от CSRF, и почему это небольшое изменение на самом деле является очень ценным.


Во-первых, что такое CSRF-атака? Согласно первоначальному замыслу всемирная паутина должна быть наполнена взаимосвязанным контентом, где одна страница могла бы, например, показывать изображения с другой и ссылаться на другие страницы без каких-либо ограничений. За кулисами работает веб-браузер, загружающий различные ресурсы, делая запросы к серверам. Серверы декодируют запросы и выдают ответ, направляя соответствующий контент. Интернет не меняет состояние, а серверы изначально не знают цели запроса. Сервер понимает, что браузер запрашивает изображение Эйфелевой башни, но не знает, что браузер собирается использовать эту картинку при отображении статьи из Википедии.


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


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


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


Однако с помощью CSRF-уязвимостей умный злоумышленник может сделать очень многое. Вот восемь очевидных действий для разных ситуаций:


1. Сделать слепой произвольный запрос по любому маршруту в качестве пользователя


В общем-то, это неинтересная и абстрактная угроза. И все же посмотрите на любое веб-приложение. Ведь непременно должно быть что-то неприятное, что можно сделать с помощью CSRF? Например, отправить компрометирующее сообщение от лица незадачливого пользователя или забронировать кому-нибудь билеты на рейс в Таджикистан? А если жертвой является администратор, возможно, злоумышленники могут присвоить себе статус привилегированного пользователя?


2. Сделать запрос и узнать его продолжительность


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


Однако никто серьезно не защищается от атак по времени, скажем, при поиске. Например, предположим, что у вас есть сайт службы знакомств, а злоумышленник делает запрос через браузер жертвы, скажем, Сары, по маршрутам messages/search?query=kevin%20mitchell и messages/search?query=blurghafest. Если достоверно известно, что первый запрос занимает больше времени, чем второй (причем необязательно намного), может пролиться кровь. Или, как минимум, где-то далеко произойдет неприятность и появится недовольный клиент.


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


3. Заставить пользователя выйти из системы


Страницы выхода из системы зачастую не защищены от CSRF-атак, так как важно дать пользователям возможность выйти из учетной записи в любой ситуации. Сюда входят ситуации, когда пользователь отключает файл CSRF cookie, используя инструментарий разработчика. Если во главу угла ставится возможность выхода из системы, страницы выхода из учетной записи становятся хорошей целью для CSRF-атак.


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


4. Заставить пользователя выйти из системы и снова войти


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


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


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


5. Изменить адрес электронной почты пользователя и запросить восстановление пароля


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


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


6. Превратить уязвимость Self-XSS в XSS


CSRF-атака может превратить уязвимость self-XSS, которая является мелкой проблемой, в XSS, которая является огромной проблемой.


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


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


Уязвимость Self-XSS представляет собой значительно меньшую угрозу безопасности. В этом случае пользователи могут вставлять скрипты в веб-сайт, но эти скрипты видны только при использовании собственных учетных записей этих пользователей, а не учетных записей других пользователей. Таким образом, в самом неприятном случае пользователь может причинить ущерб самому себе.


Вот реальный пример уязвимости Self-XSS. Несколько лет назад я обнаружил, что система записи на курсы в моем университете имеет страницу с описанием курсов, в которую можно вписывать скрипты. Этот момент считался несущественным, поскольку на этой странице могли писать только преподаватели, а они вряд ли стали бы добавлять сюда вредоносные скрипты.


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


7. Замести следы


Если злоумышленник также является пользователем атакуемого веб-приложения, CSRF-атака становится хорошим способом скрыть следы. Хотите вставить XSS-скрипт в сообщение на форуме, но не хотите делать это под собственной учетной записью, чтобы не попасться? В таком случае совершите CSRF-атаку на другого пользователя и используйте его браузер и идентификационные данные для вставки XSS.


Если пользователь не обладает по-настоящему глубоким пониманием, он никогда не узнает, откуда пришел этот CSRF-удар.


8. Распространять вредоносное ПО


Позволяет ли ваш сервис пользователям хранить файлы? Многие типы файлов, такие как .docx, pdf, jpeg и другие исторически используются для сокрытия вредоносного ПО из-за багов программ, которые их читают.


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


Заключительные замечания


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

Подробнее..

Доступность это просто, Или 5 смертных грехов доступности

10.12.2020 12:12:32 | Автор: admin

Привет, Хабр! Меня зовут Алексей Устинов, я Frontend-разработчик в Delivery Club. В свободное время я интересуюсь вопросами доступности интерфейсов. Это первая из двух статей, в которых я хочу рассказать о проблемах с доступностью в вебе. Я расскажу про 5 простых правил, соблюдая которые можно значительно улучшить доступность сайта. Также мы рассмотрим самые распространённые проблемы, я объясню, почему они являются проблемами, и дам простые советы по их решению. Во второй статье я, наоборот, приведу примеры элементов страницы, сделать доступными которые совсем нетривиальная задача.

Я уверен, что ты, %username%, слышал про правило 80/20: 80% результата можно достичь за 20% трудозатрат, а на достижение остальных 20% необходимо потратить 80% трудозатрат. Именно это правило объединяет эту и следующую статью.

Как работает скринридер

Основная цель программ экранного доступа, таких как NVDA, VoiceOver и других, это объяснить пользователю, что за элемент сейчас находится в фокусе, и, самое главное, рассказать о его предназначении. Если элемент содержит в себе какую-то текстовую информацию, то скринридер заботливо прочитает её для пользователя.

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

Грех 1. Бардак в заголовках

В HTML существует шесть уровней заголовков, которые обозначаются тегами от H1 до H6 и используются именно в этом порядке, создавая иерархическую структуру.

Пример иерархии заголовковПример иерархии заголовков

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

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

Я часто встречаю страницы, на которых есть несколько заголовков H1, или на которых вслед за H2 идет, например, H4.

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

Варианты решения

  • Объявлять заголовки с помощью тегов H1H6.

  • Использовать заголовки в иерархической последовательности от H1 до H6.

Грех 2. Кнопки с неопределенным назначением

Пример кнопок недоступных для скринридераПример кнопок недоступных для скринридера

Посмотрите на картинку: вы понимаете, что делает каждая из кнопок? Если да, то как вы это поняли? О значении кнопок вам рассказывают иконки, но что делать, если вы не видите иконок? Тогда вы, в лучшем случае, услышите что-то в роде button, а в худшем даже не сможете попасть фокусом на этот элемент.

Худший случай происходит, когда кнопка сделана с помощью div и стилизована под кнопку с помощью CSS. Рядовой пользователь, вооруженный мышкой, кликнет на этот div, JavaScript обработает событие, произойдёт какая-то магия, и пользователь увидит результат. Скринридер же просто не поймёт, что это кнопка.

Если же кнопка сделана через элемент button, то скринридер догадается, что это кнопка, но вот её предназначение он будет брать из атрибута aria-label или текста, находящегося внутри тега button.

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

Варианты решения

  • Добавлять назначение кнопки.

Грех 3. Невидимые картинки

Изображение часто передаёт ценную информацию. В большинстве случае ключевую мысль изображения можно описать в одном-двух предложениях. Именно для этой цели существует атрибут alt (альтернативный текст), в который можно вписать, что изображено на картинке, или с какой целью автор вставил её в текст.

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

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

Варианты решения

  • Всегда добавлять описание к картинкам в атрибут alt.

Грех 4. Отсутствие описания форм

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

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

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

Другой проблемой форм является капча. Кажется, это очевидно всем, что незрячий или слабовидящий пользователь не сможет выбрать картинки с автобусами.

пример капчипример капчи

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

Варианты решения

  • К каждому инпуту добавлять тег label с достаточным описанием.

  • Не использовать капчу, которую можно разгадать только при помощи зрения.

Грех 5: фоновая музыка или автовоспроизведение

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

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

сайт с огромным количеством рекламных попаповсайт с огромным количеством рекламных попапов

Варианты решения

  • Не использовать фоновую музыку, которую нельзя выключить.

  • Не использовать видеоплееры, которые начинают играть при переходе на страницу.

  • Не использовать плееры, кнопки которых недоступны для скринридера.

Вывод

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

Всем добра!

Подробнее..

Доступность это не так просто

22.12.2020 14:23:50 | Автор: admin


Привет, Хабр! В предыдущей статье я рассказывал о простых случаях проблем с доступностью, исправив которые можно сделать свой сайт или web-приложение гораздо доступнее. Я упоминал о правиле 80/20 и писал о проблемах, которые при наименьших затратах дают наибольший результат. Сегодня я бы хотел поговорить о другой группе проблем, которые входят в 20% и для решения которых нет готовых рецептов вроде всегда заполняйте атрибут alt или используйте верные заголовки.

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

Формализуем проблему


Как я уже говорил, для некоторых проблем в сфере доступности невозможно предложить какое-то простое решение. Эти проблемы очень вариативны, а иногда и вовсе уникальны для конкретного приложения. Помимо этого, ситуация осложняется различиями в работе разных скринридеров в разных браузерах и на разных операционных системах. Дополняет всё это то, что решение лежит на стыке двух дисциплин: доступности с её стандартами и Interaction Design (Проектирование взаимодействия) с её достаточно гибкими правилами.

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

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

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

К таким элементам можно отнести:

  • табы;
  • модальные окна;
  • аккордеон;
  • меню (в том числе с большой вложенностью).

Каждый компонент их этого списка можно условно разделить на две составляющие:

  • триггер элемент, запускающий действие;
  • целевой контент элемент, который содержит в себе кусочек видоизмененного контента.

Реализация триггера


Первое, с чем я предлагаю разобраться, это какой базовый элемент будет лежать в основе триггера. Использование элементов, которые сразу являются фокусируемыми и интерактивными, я считаю хорошей идеей. Поэтому сразу отбрасываю всевозможные реализации с помощью div, span и т. д.

В итоге я прихожу к первому вопросу: должен ли быть триггер ссылкой или кнопкой?

Ответ на этот вопрос звучит примерно так: в зависимости от ситуации, но в целом, вы не ошибётесь, если будете всегда использовать кнопку.

Кнопка это элемент, предназначенный для запуска каких-либо интерактивных элементов внутри страницы. Поэтому пользователь, нажимая на кнопку, будет готов, что на странице что-то изменится. Кажется, это то, что нам нужно. Тем не менее, я считаю, что ссылки имеют некоторые преимущества в некоторых случаях.

Поэтому я задаю себе второй вопрос: должен ли изменившийся контент получить фокус?
И опять ответом на этот вопрос будет фраза в зависимости от ситуации. Но можно помочь себе, просто посмотрев на DOM-дерево и оценив, насколько далеко триггер находится от целевого контента.

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

<button>Trigger Text</button> <div id="target">   <p>Target content.</p></div>

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

<a href="#target">Trigger Text</a>  <div id="target">  <p>Target content.</p></div>


Реальный пример


Предположим, в макете, предоставленном дизайнером, имеется элемент Войти, расположенный в шапке сайта. И, согласно дизайну, по нажатию должно открыться модальное окно с формой входа. Сам код модального окна, скорее всего, находится в конце DOM-дерева. В этом случае использование ссылки не кажется мне плохой идеей.

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

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

Далее я добавляю на страницу немного JavaScript, чтобы убедиться, что пользователи клавиатуры и мыши могут взаимодействовать с созданным компонентом. Конечно, не обходится без небольшой магии с tabindex и методом focus(), которые заслуживают отдельной статьи.

Теперь самое время подумать о пользователях скринридеров. Первое, что стоит сделать это добавить атрибуты aria-expanded в триггер и aria-hidden в целевой контент.

// Таргет не активирован
Триггер - aria-expanded="false",
Целевой контент - aria-hidden="true".

// Пользователь нажал на таргет элемент
Триггер - aria-expanded="true",
Целевой контент - aria-hidden="false".


Ещё существует атрибут aria-controls, который позволяет явно указать взаимосвязь между целевым компонентом и триггером.

<button aria-controls="target">Trigger Text</button><div id="target">  <p>Target content.</p></div>

Правда, он не всегда работает так, как это можно ожидать.

В качестве заключения


Для более наглядного примера я реализовал два codepan: один с триггером в виде кнопки, а второй со ссылкой (кнопка, ссылка). В чём разница, спросите вы? Всё просто: в примере со ссылкой целевой контент сразу получил фокус без каких-то дополнительных телодвижений со стороны разработчика.

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

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

И помните, что тот факт, что вы дочитали этот материал до конца, означает, что вы знаете, как решать проблемы с доступностью лучше, чем большинство разработчиков.

Спасибо за внимание, всем добра!
Подробнее..

Перевод Искусство компонентов. Пишем карточку контакта Facebook Messenger

13.01.2021 18:13:38 | Автор: admin
Вполне возможно оценить компонент и сказать, что он легко пишется на HTML и CSS. Соглашусь, это легко, когда вы работаете, только чтобы практиковаться, но в реальном проекте всё по-другому. Идеальный адаптивный компонент, который вы только что создали, быстро перестаёт работать, когда сталкивается с реальным контентом настоящего проекта. Почему? Потому, что, пока вы рассуждаете о разработке компонента, вы можете упустить крайние случаи. Я покажу простой на первый взгляд компонент, за которым стоит огромная работа. Ради реалистичности это будет пример прямо из Facebook Messenger.




Начнем


Я беру очень простой компонент Facebook Messenger, посмотрите на скриншот ниже:


В этом сайдбаре списком карточек перечисляются люди, которым я писал на Facebook. Здесь меня интересует только карточка. Как вы напишете её на HTML/CSS? Да очень легко, правда? Есть соблазн сказать, что это всего лишь картинка и слой рядом с ней. Вот о чём можно подумать:



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

<div class="card">  <img class="card__image" src="assets/shadeed.jpg" alt="" />  <div><h3>Ahmad Shadeed</h3><p>You: Thanks, sounds good! . 8hr</p><img class="card__seen" src="assets/shadeed.jpg" alt="" />  </div></div>

.card {  position: relative;  display: flex; /* [1] */  align-items: center; /* [2] */  background-color: #fff;  padding: 8px;  border-radius: 7px;  box-shadow: 0 3px 15px 0 rgba(0, 0, 0, 0.05);}.card h3 {  font-size: 15px;}.card p {  font-size: 13px;  color: #65676b;}.card__image {  width: 56px;  height: 56px;  border-radius: 50%;  margin-right: 12px;}.card__seen {  position: absolute; /* [3] */  right: 16px;  top: 50%;  transform: translateY(-50%);  width: 16px;  height: 16px;  border-radius: 50%;}

Я выделил несколько строчек, их я хочу объяснить:

  1. Использовался flexbox, потому что у нас горизонтальный дизайн, а flexbox хорошо подходит для него.
  2. Дочерние элементы нужно центрировать вертикально.
  3. Значок позиционирован абсолютно, также он центрируется вертикально.

Ломаем компонент


Здесь нет ничего плохого, но компонент не масштабируется, так что покажу другой вариант:



Синий значок справа означает, что пришло новое сообщение, которое я ещё не открывал. Зелёный цвет на аватаре показывает, что пользователь сейчас в сети.

Обратите внимание: у нас есть два новых значка. Как лучше добавить их на карточку? Если вы обратитесь к CSS, который я написал для самого первого компонента, то увидите, что там есть класс .card_seen для маленьких аваторов пользователей справа. В этом варианте .card_seen должен быть заменён синим значком. С уже написанными HTML и CSS, не изменив HTML, написать такое невозможно.

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

Все вариации


Ниже я показываю все вариации компонента. Очень старался описать их все (да, я нарисовал всё это вручную).



Но и этого мало: мы должны учитывать стили тёмной темы.



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

Интервалы


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



В разработке и реализации UI на HTML и CSS одна из ключевых вещей, которой нужно уделить внимание, это интервалы. Если интервалы недооценить, позже, возможно, придётся изменить сам UI.

Области компонента


Чтобы написать приличный компонент, нужно сначала тщательно продумать разметку. У нас есть две области компонента с несколькими вариациями: аватаром и областью контента.

Аватар




Чтобы работать над HTML аватара, сначала нужно разобраться с его состояниями. Вот возможные варианты:

  • Один аватар.
  • Один аватар со значком онлайн-статуса.
  • Несколько аватаров для группового чата.
  • Несколько аватаров со значком онлайн-статуса.

Учитывая HTML ниже, мы хотим удостовериться, что .card__avatar работает со всеми вариантами аватаров выше.

<div class="card">  <div class="card__avatar"></div>  <div class="card__content"><!-- Name, message, badge.. -->  </div></div>

Один аватар


Давайте увеличим масштаб HTML и сосредоточимся на первом варианте, то есть на одном аватаре. У аватара должна быть граница (или внутренняя тень), чтобы он выглядел как круг, даже если он полностью белый.



В CSS невозможно применить внутреннюю box-shadow к элементу img. У нас есть два варианта:

  • Дополнительный div с прозрачным border.
  • Можно написать svg.

Цель внутренней границы показать контур вокруг аватара в случаях, когда у нас:

  • Полностью белый аватар светлой темы;
  • Полностью чёрный аватар тёмной темы.



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



div для внутренней границы


В этом решении дополнительный элемент (здесь это div) абсолютно расположен над изображением с непрозрачностью 0.1.

<div class="card__avatar">  <img src="assets/shadeed.jpg" alt="" />  <div class="border"></div></div>

.card__avatar {  position: relative;}.card__avatar img {  width: 56px;  height: 56px;  border-radius: 50%;}.border {  position: absolute;  width: 56px;  height: 56px;  border: 2px solid #000;  border-radius: 50%;  opacity: 0.1;}

Это решение работает, но у него есть ограничения, о которых я скоро расскажу.

Работаем с svg


В этом решении воспользуемся элементом svg. Вот идея: использовать круглую маску для аватара, а для внутренней границы элемент circle. SVG отлично подходит для этого.

<svg role="none" style="height: 56px; width: 56px">  <mask id="circle"><circle cx="28" cy="28" fill="white" r="28"></circle>  </mask>  <g mask="url(#circle)"><image  x="0"  y="0"  height="100%"  preserveAspectRatio="xMidYMid slice"  width="100%"  xlink:href="http://personeltest.ru/aways/habr.com/assets/shadeed.jpg"  style="height: 56px; width: 56px"></image><circle class="border" cx="28" cy="28" r="28"></circle>  </g></svg>

.border {  stroke-width: 3;  stroke: rgba(0, 0, 0, 0.1);  fill: none;}

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

Единственный аватар со значком онлайн-статуса


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



Как это сделать? Оказывается, если воспользоваться SVG-решением для того самого единственного аватара, проблема легко решается при помощи маски SVG.

<svg role="none" style="height: 56px; width: 56px">  <mask id="circle"><!-- [1] --><circle cx="28" cy="28" fill="white" r="28"></circle><!-- [2] --><circle cx="48" cy="48" fill="black" r="7"></circle>  </mask>  <!-- [3] -->  <g mask="url(#circle)"><image  x="0"  y="0"  height="100%"  preserveAspectRatio="xMidYMid slice"  width="100%"  xlink:href="http://personeltest.ru/aways/habr.com/assets/shadeed.jpg"  style="height: 56px; width: 56px"></image><circle class="border" cx="28" cy="28" r="28"></circle>  </g></svg>

Позвольте объяснить этот код:

  1. Круг маскирует аватар.
  2. В правом нижнем углу аватара вырезается маленький кружок.
  3. Группа, которая содержит circle и image для прозрачной внутренней границы.

Вот рисунок, который объясняет, как несколько окружностей работают в качестве маски. Это какая-то магия, правда?



Так выглядит HTML аватара со значком онлайн-статуса.

<div class="card__avatar">  <svg role="none" style="height: 56px; width: 56px"><mask id="circle">  <circle cx="28" cy="28" fill="white" r="28"></circle>  <circle cx="48" cy="48" fill="black" r="7"></circle></mask><g mask="url(#circle)">  <imagex="0"y="0"height="100%"preserveAspectRatio="xMidYMid slice"width="100%"xlink:href="http://personeltest.ru/aways/habr.com/assets/shadeed.jpg"style="height: 56px; width: 56px"  ></image>  <circle class="border" cx="28" cy="28" r="28"></circle></g>  </svg>  <div class="badge"></div></div>

.card__avatar {  position: relative;  display: flex;  margin-right: 12px;}.badge {  position: absolute;  right: 3px;  bottom: 3px;  width: 10px;  height: 10px;  background: #5ad539;  border-radius: 50%;}

Когда подобный этому компонент должен адаптироваться под разные темы, настоятельно рекомендуется хранить изменяемые цвета в переменных СSS.

:root {  --primary-text: #050505;  --secondary-text: #65676b;  --bg-color: #fff;}html.is-dark {  --primary-text: #e4e6eb;  --secondary-text: #b0b3b8;  --bg-color: #242526;}.card {  background-color: var(--bg-color);}.card__title {  color: var(--primary-text);}.card__subtitle {  color: var(--secondary-text);}



Несколько аватаров в групповом чате


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

.card__avatar {  width: 56px;  height: 56px;}


Этот вариант требует изменить разметку вот так:

<div class="card__avatar card__avatar--multiple">  <svgclass="avatar avatar-1"role="none"style="height: 36px; width: 36px"  ></svg>  <svgclass="avatar avatar-2"role="none"style="height: 36px; width: 36px"  ></svg>  <div class="badge"></div></div>

.card__avatar--multiple {  position: relative;  width: 56px;  height: 56px;}.card__avatar--multiple .avatar {  position: absolute;}.card__avatar--multiple .avatar-1 {  right: 0;  top: 0;}.card__avatar--multiple .avatar-2 {  left: 0;  bottom: 0;}.card__avatar--multiple .badge {  right: 6px;  bottom: 6px;}



Контент


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



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



Первая часть


Давайте внимательно посмотрим на разметку области контента.

<div class="card__content">  <div class="card__content__start"><h3>Ahmad Shadeed</h3><div class="row">  <p>You: Thanks, sounds good. What about doing a webinar, too?</p>  <span class="separator">.</span>  <time>8hr</time></div>  </div>  <div class="card__content__end"><!-- The indicator (new message, seen, muted, sent) -->  </div></div>

.card__content {  display: flex;  flex: 1;}.card__content__start {  display: flex;  flex: 1;}.card__content__start .row {  display: flex;  align-items: center;}.card__content__end {  display: flex;  justify-content: center;  align-items: center;  margin-left: 12px;}.separator {  margin-left: 4px;  margin-right: 4px;}

С кодом выше область содержимого выглядит, как показано ниже (это скриншот из Firefox).



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



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

  • Установите min-width: 0 для дочерних элементов flex. Зачем? Я расскажу позже.
  • Обрежьте текст через свойства overflow, white-space, и text-overflow. Я уже писал подробнее об обработке короткого и длинного контентов.

Я добавил к имени и абзацу код ниже:

.card__content__start h3,.card__content__start p {  overflow-x: hidden;  white-space: nowrap;  text-overflow: ellipsis;}

Но этот код не решает нашу проблему автоматически, когда мы используем flexbox. Обратите внимание на то, что делает приведённый выше CSS:



И вот причина: flex-элементы не сжимаются сильнее минимального размера контента. Чтобы решить эту проблему, нужно установить min-width: 0 в .card__content и card__content__start.



Вторая часть


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



В этой части сосредоточимся на .card__content__end и на содержании внутри него.

<div class="card__content">  <div class="card__content__start"><!-- The name and message -->  </div>  <div class="card__content__end"><!-- The indicator (new message, seen, muted, sent) -->  </div></div>

У элемента .card__content__end не должно быть таких стилей, как цвет или размер шрифта, этот элемент будет служить только родительским элементом определённого компонента.

Новое сообщение


Я посмотрел, как Facebook работает с индикатором нового сообщения; оказалось, что это кнопка с надписью Mark as read.

<div role="button" aria-label="Mark as read" tabindex="0"></div>



Не знаю, почему команда Facebook выбрала div, а не button. С встроенной кнопкой не нужны атрибуты role, aria-label и tabindex. Все они встроены в кнопку.

Единственный аватар около поста


Такой аватар ничем не отличается от аватара пользователя. В нем применяется элемент svg с атрибутом aria-label, который показывает имя пользователя.


<svg aria-label="Ahmad Shadeed" role="img">  <!-- Mask and image --></svg>


Несколько аватаров около поста


Если честно, это мой любимый вариант. Мне очень нравится, как это сделала команда Facebook.


Вы видите границу между двумя аватарами? Сначала кажется, что это граница CSS для первого аватара. Если вы так подумали, извините, но вы ошиблись, как и я вначале.

Граница сделана при помощи маски SVG. Да, вы не ослышались!


Маска работает так:



Невероятно. Конкретно здесь мне нравится пользоваться SVG.

Контент справа налево


Когда макет LTR (слева направо), а текст сообщения написан на арабском языке, направление текста тоже должно быть RTL (справа налево).



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

<div class="card__content">  <div class="card__content__start" style="direction: rtl"></div>  <div class="card__content__end"></div></div>

Переворачиваем компонент


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



Элементы размещаются с помощью flexbox, поэтому нужно только перевернуть поля.

/* LTR */.card__content__end {  margin-left: 12px;}/* LTR */.card__content__end {  margin-right: 12px;}


Доступность


Работа с клавиатуры


Продукт, который работает с миллиардами пользователей, должен быть доступен для всех. Что касается компонента из этой статьи, я протестировал его в Chrome и Firefox и заметил такие проблемы:

  • Стили фокуса отлично работают в Chrome, но в Firefox нет визуальной подсказки.
  • Фокуса на меню действий, которое появляется при наведении курсора, можно добиться в Firefox, и я не могу получить к нему доступ с клавиатуры в Chrome.



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



К сожалению, в Chrome я не смог достучаться до меню действий с помощью клавиатуры.

Список карточек


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

<div role="grid">  <div role="row"><div role="gridcell">  <a href="#"><!-- The component lives here -->  </a></div>  </div>  <div role="row"><div role="gridcell">  <a href="#"><!-- The component lives here -->  </a></div>  </div></div>

Несколько аватаров


Для группового чата есть несколько аватарок индикатора просмотров. Здесь роли ARIA располагают ячейки в ряд.
<div role="grid">  <div role="row"><!-- 1st avatar --><div role="cell"></div><!-- 2nd avatar --><div role="cell"></div>  </div></div>

Посмотрите на демо с сайта Codepen. Всех вариантов здесь нет, я просто проверял их.

Заключение


В этой статье я хотел бы подчеркнуть, что простейший компонент требует огромной работы. Между прочим, все объяснения выше касались только HTML и CSS. А как насчёт JavaScript? Это уже другая история.

Я наслаждался работой, пока писал эту статью, и обязательно поработаю над чем-то подобным в будущем. И еще рад сообщить вам, что я написал электронную книгу об отладке CSS. Если вам интересно, кликните по ссылке debuggingcss.com и посмотрите книгу бесплатно. Вам понравился мой контент? Тогда вы можете заплатить за мой кофе. Большое спасибо!




Подробнее..

Оптимизация графики в Voximplant Kit

24.03.2021 14:22:50 | Автор: admin

Что делать, если сценарий крутой и сложный, но из-за этого начинает тормозить? Данным вопросом задались наши разработчики Voximplant Kit и придумали функцию оптимизации. Продолжая серию обновлений Кита, расскажем, как оптимизация заставила большие сценарии летать и с какими проблемами мы столкнулись в процессе её создания.

Почему надо оптимизировать

Многим знакома проблема производительности, вызванная наличием слишком большого количества элементов на странице. Что это значит? В нашем случае чем больше элементов в сценарии Voximplant Kit, тем больше это влияет на скорость визуализации перемещения блоков по холсту (всех вместе и по отдельности), а также на скорость визуализации перемещения и масштабирования самого холста.

Мы рассмотрели разные варианты и пришли к выводу, что в качестве решения отлично подойдёт CSS свойство will-change, позволяющее заранее проинформировать браузер об изменениях, которые могут быть применены к элементу. Благодаря этому свойству можно настроить оптимизацию до начала изменений во избежание затрат на запуск операций, негативно влияющих на отзывчивость страницы.

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

<svg ... > <---- Холст <g transform="matrix(1,0,0,1,224,444)"> <---- Группа элементов внутри svg  <rect>  <rect>

Реализация

У наших разработчиков появилась идея обернуть SVG в div-элемент, чтобы применять все трансформации сначала к нему, а затем при необходимости к самому SVG-элементу с холстом. После того, как трансформации стали применяться к <div>, мы смогли использовать will-change: transform для их отслеживания:

<div> <---- div-обёртка, к которой применяется оптимизация  <svg ... > <---- Холст   <g> <---- Группа элементов внутри svg    <rect>    <rect>

Но появилась ещё одна проблема использование will-change инициирует создание нового слоя, и чем больше ширина и высота элемента, к которому это св-во применяется, тем больше расходуется оперативной памяти для хранения слоя. Справиться с этим помогло уменьшение масштаба SVG в 10 раз. Так, например, при масштабе холста =200% для слоя сwill-change требовалось300 мегабайтоперативки , а после уменьшения масштаба стало нужно всего около3 мегабайт.

Чтобы это осуществить, выставляем параметр zoom = 0.1 и подключаем к работе методtransformToCenterViewport, после чего применяем те же трансформации к div-элементу:

if (isPerfMode) {  this.el.classList.add('perf-mode');  // Меняем масштаб перед включением performance mode  const prevScale = this._viewportMatrix.a;  const point = this.getViewPortCenter();  const zoom = 0.1;       // Уменьшаем исходный svg, чтобы will-change тратил меньше оперативной памяти  this.transformToCenterViewport(point, zoom, true, false, true);  this.initScale = this._viewportMatrix.a;  this.createMatrix();     this.isPerfMode = true;       // Применяем трансформации к элементу-обертке  this.startPerformance();  this.transformToCenterViewport(point, prevScale, false, false, true);}

Т.к. при переходе в режим оптимизации мы уменьшаем SVG, холст становится очень маленьким и неудобным для работы. Чтобы это исправить, применим обратное масштабирование непосредственно к div-элементу:

public startPerformance(force = false) {  ...  this.isPerformance = true;    // Получаем размер области с блоками и отступ от левого угла вьюпорта  const { x, y, width, height } = this.layers.getBBox();  const initScale = this.initScale;    // Ширина и высота для обёртки и смещение по оси x и y для области с блоками  const wrapW = Math.floor(width * initScale) + 2;  const wrapH = Math.floor(height * initScale) + 2;  const layerX = -x * initScale;  const layerY = -y * initScale;    // this.wrapMatrix - матрица div-элемента с холстом   this.wrapMatrix.e = +(this._viewportMatrix.e + x * this._viewportMatrix.a);   this.wrapMatrix.f = +(this._viewportMatrix.f + y * this._viewportMatrix.d);   this.svgWrapper.style.width = wrapW + 'px';   this.svgWrapper.style.height = wrapH + 'px';   this.svgWrapper.style.transform = this.wrapMatrix.toString();   this.svgWrapper.style.willChange = 'transform'; this.layers.style.transform = `matrix(${initScale},0,0,${initScale},${layerX} ,${layerY} )`;}

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

После завершения масштабирования (событие о скролле), св-во will-change удаляется на 0.1 секунды и затем устанавливается заново. Это заставляет браузер повторно растрировать слой, возвращая пропавшие детали изображения:

// Добавляем 3d трансформацию, чтобы слой не был удаленthis.svgWrapper.style.transform = this.wrapMatrix.toString() + ' translateZ(0)';this.transformFrameId = requestAnimationFrame(() => {  // Устанавливаем св-во will-change для применения в следующем кадре  this.svgWrapper.style.willChange = '';  this.transformFrameId = requestAnimationFrame(() => {    this.svgWrapper.style.willChange = 'transform';    this.svgWrapper.style.transform = this.wrapMatrix.toString();  });});

Осталось внести последний фикс всегда отображать перемещаемый блок поверх других. В JointJS для перемещения блоков и линков по оси Z существуют методы toFront и toBack (аналог z-index в HTML). Принцип их работы заключается в сортировке элементов и перерисовке блоков и линков, это вызывает задержки.

Наши разработчики придумали следующее: блок, с которым мы взаимодействуем, временно ставится в конец дерева элементов внутри SVG (элемент с самым высоким z-index находится в конце списка) на событие mousedown, а затем возвращается на прежнее место на событие mouseup.

Принцип работы

Режим оптимизации можно протестировать во всех браузерах на основе Chromium (Chrome, Opera, Edge, Yandex Browser и т.п.), а также в браузере Safari. Для сценариев, содержащих от 50 блоков, функция включается автоматически. Самостоятельно включить или отключить её можно, перейдя в меню настроек сценария в правом верхнем углу:

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

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

Без оптимизации работа с холстом и его элементами выглядит примерно так (на разных компьютерах с разными мощностями результат может отличаться):

Подключаем оптимизацию и вуаля!

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

Надеемся, что статья была интересной, мы будем продолжать улучшать продукт и делиться успехами и лайфхаками с вами!

Подробнее..

Перевод Почему стоит использовать тег ltpicturegt вместо ltimggt

05.05.2021 10:13:29 | Автор: admin
image

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

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

Выбор между тегами picture и img может показаться мелким решением, но сделав правильный выбор, вы сможете повысить и удобство для пользователя, и производительность.

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

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

Почему тега img недостаточно для современных веб-приложений?


Как все мы знаем, тег Img в течение длительного периода времени был одним из фундаментальных элементов HTML, и никто не сомневался в его простоте и применимости.

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

Все эти вопросы можно сгруппировать в две большие категории:

  1. Смена разрешения проблема передачи изображений меньшего размера для устройств с маленькими экранами.
  2. Ориентация графики проблема отображения различных изображений при разных размерах экрана.

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

Смена разрешения при помощи атрибутов srcset и sizes


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

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

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


Проблема загрузки изображения сверху вниз

Эту проблему можно легко решить тегом picture при помощи атрибутов srcset и sizes.

<picture>   <source      srcset="small-car-image.jpg 400w,              medium-car-image.jpg 800w,              large-car-image.jpg 1200w"      sizes="(min-width: 1280px) 1200px,             (min-width: 768px) 400px,             100vw">   <img src="medium-car-image.jpg" alt="Car"></picture>

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

Атрибут sizes задаёт пространство, которое изображение будет занимать на экране. В показанном выше примере изображение займёт до 1200px, если минимальная ширина экрана равна 1280px.

Тем не менее, рекомендуется не использовать тег Picture только для смены разрешения, потому что ту же задачу можно решить с помощью новой версии тега Img (имеющей поддержку большего количества браузеров).

<img srcset="small-car-image.jpg 400w,             medium-car-image.jpg 800w,             large-car-image.jpg 1200w"     sizes="(min-width: 1280px) 1200px,            (min-width: 768px) 400px,            100vw"          src="medium-car-image.jpg" alt="Car">

Однако в большинстве случаев нам нужно решать проблему и смены разрешения, и ориентации графики, и лучшим решением для этого является тег picture.

Поэтому давайте посмотрим, как можно решить проблему ориентации графики с помощью тега picture.

Ориентация графики при помощи атрибута media


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

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

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

<picture>      <source ....>   <source ....>   <source ....></picture>

Затем можно использовать атрибут media для задания различных условий среды, в которых будут использоваться эти источники. Также можно использовать атрибуты srcset и sizes аналогично тому, о чём мы говорили в предыдущем разделе.

В показанном ниже примере демонстрируется полная реализация ориентации графики и смены разрешения при помощи тега picture.

<picture>        <source media="(orientation: landscape)"                   srcset="land-small-car-image.jpg 200w,              land-medium-car-image.jpg 600w,              land-large-car-image.jpg 1000w"                   sizes="(min-width: 700px) 500px,             (min-width: 600px) 400px,             100vw">        <source media="(orientation: portrait)"                   srcset="port-small-car-image.jpg 700w,              port-medium-car-image.jpg 1200w,              port-large-car-image.jpg 1600w"                   sizes="(min-width: 768px) 700px,             (min-width: 1024px) 600px,             500px">        <img src="land-medium-car-image.jpg" alt="Car"></picture>

Если экран находится в альбомной ориентации, то браузер будет отображать изображения из первого набора, а если в портретной, то из второго набора. Кроме того, можно использовать атрибут media с параметрами max-width и min-width:

<picture>     <source media="(max-width: 767px)" ....>     <source media="(min-width: 768px)" ....></picture>

Последний тег img используется для обратной совместимости с браузерами, не поддерживающими теги picture.

Использование с частично поддерживаемыми типами изображений


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

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

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

<picture>  <source srcset="test.avif" type="image/avif">  <source srcset="test.webp" type="image/webp">  <img src="test.png" alt="test image"></picture>

В показанный выше пример включены три типа изображений в форматах avif, webp и png. Сначала браузер попробует формат avif, если не получится, то попробует webp. Если браузер не поддерживает ни один из них, то использует изображение png.

Ситуация с тегом picture стала ещё интереснее, когда разработчики Chrome объявили о том, что во вкладке Rendering инструментов DevTools появится две новые эмуляции для эмулирования частично поддерживаемых типов изображений.

Начиная с Chrome 88 и далее можно использовать Chrome DevTools для проверки совместимости браузера с типами изображений.


Использование Chrome DevTools для эмулирования совместимости изображений

В заключение


Хоть мы и говорили о том, насколько лучше тег picture по сравнению с тегом img, я уверен, что img не умер и умрёт ещё не скоро.

Если мы будем с умом использовать имеющиеся у него атрибуты srcset и size, то можем выжать из тега img максимум. Например, можно решить проблему смены разрешения при помощи одного только тега img.

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

Среди прочих достоинств тега picture способность работать с частично поддерживаемыми типами изображений и поддержка Chrome DevTools.

Однако оба эти элемента имеют свои плюсы и минусы. Поэтому нам нужно обдумывать и выбирать наиболее подходящий к нашим требованиям элемент.



На правах рекламы


Эпичные серверы это VDS для размещения сайтов от маленького интернет-магазина на Opencart до серьёзных проектов с огромной аудиторией. Создавайте собственные конфигурации серверов в пару кликов!

Подписывайтесь на наш чат в Telegram.

Подробнее..

Перевод 9 репозиториев, о которых должен знать каждый веб-разработчик

20.12.2020 18:08:28 | Автор: admin
В наши дни GitHub это универсальное хранилище всего, что связано с веб-разработкой. Фреймворки, демоверсии, всевозможные коллекции вероятно, нет ничего такого, что вы не могли бы найти на GitHub. Однако в этом огромном количестве и заключается проблема. Есть классные вещи, о которых вы, вероятно, никогда не услышите просто потому, что репозиториев много. Сегодня, специально к старту нового потока курса по веб-разработке мы делимся подбокой некоторых из самых популярных репозиториев GitHub, о которых вы должны знать, каждый из которых имеет по крайней мере ~30 000 звёзд.




Realworld


Первый репозиторий в этом списке Realworld. Его создатели называют его не иначе как матерью всех демоприложений. Смелое заявление, конечно, но не думаю, что это преувеличение. Realworld образцовый клон Medium.com. Но не только им. Репозиторий позволяет вам выбирать различные реализации на фронтенде и бэкенде, которые можно с удовольствием смешивать. Vue.js + Node / Express или React /Redux + Rust? Всё это есть! Realworld показывает, как точно такое же приложение для блога построить практически на любом популярном языке или фреймворке. Это потрясающе!

Вы еще не знаете JS


Этот репозиторий популярная серия книг Кайла Симпсона, широко известного под псевдонимом Getify. Книги глубоко погружаются в механику JavaScript и охватывают следующие темы:

  • Введение.
  • Области видимости и замыкание.
  • Классы и объекты.
  • Типы и грамматика.
  • Синхронность и асинхронность.
  • Следующий стандарт и что за его пределами.

Что здесь самое лучшее? Эти книги бесплатные! Это определённо одна из лучших серий о JavaScript, и она действительно помогла мне понять, что такое JS на самом деле. Даже если вы думаете, что хорошо знаете JavaScript, прочитайте эти книги! Вы будете удивлены, обещаю.

Руководство по стилю JavaScript Airbnb


Руководство по стилю JavaScript в Airbnb одно из самых популярных и часто используемых руководств по стилю. Оно помогает вам лучше писать код и особенно полезен в командах и в сочетании с ESLint.
Вот пример из документации, касающейся использования const вместо var:



Storybook


Storybook это среда разработки компонентов пользовательского интерфейса. Она позволяет просматривать библиотеку компонентов, состояния каждого компонента, а также интерактивно разрабатывать и тестировать компоненты! Поддерживаются React, Vue, Angular, React Native, Ember, Web Components и другие.

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

HTML5 Boilerplate


HTML5 Boilerplate это профессиональные и одни из самых популярных интерфейсных шаблонов в Интернете. Они помогут вам создавать быстрые, надёжные и адаптируемые веб-сайты или приложения. Его используют такие компании, как Microsoft, NASA и Nike.
Вот некоторые ключевые особенности:

  • Соответствие HTML5.
  • Разработка с учётом прогрессивного улучшения.
  • Наличие Normalize.css, jQuery и Modernizer.
  • Конфигурации, повышающие производительность и безопасность веб-сайта.
  • Плейсхолдер медиазапросов CSS.
  • Стили печати по умолчанию, оптимизированные для производительности.
  • Оптимизированную версию сниппета Google Universal Analytics.

Лучшие практики Node.js


Этот репозиторий представляет собой обширную коллекцию лучших практик в отношении разработки Node.js. Сейчас он состоит из более чем 80 лучших практик, руководств по стилю и советов по архитектуре.
Вы можете найти информацию о:

  • Практиках структуры проекта.
  • Методах обработки ошибок.
  • Практиках стиля кодирования.
  • Тестировании и практиках качества в целом.
  • Практиках перехода в производственную среду.
  • Методах обеспечения безопасности.
  • Практиках производительности.

Это, безусловно, прекрасный репозиторий и источник информации. Если вы разрабатываете на Node.js, посмотрите его!

Чек-листы фронтенда


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

  • Заглавие.
  • HTML.
  • Web Fonts.
  • CSS.
  • Изображения.
  • JavaScript.
  • Безопасность.
  • Производительность.
  • Доступность.
  • SEO.
  • Переводы.

Вот пример метаданных веб-приложения Apple:



NW.js


NW.js это среда выполнения приложения на базе Chromium и Node.js. Можно писать собственные приложения на HTML и JavaScript с помощью NW.js. Она также позволяет вам вызывать модули Node.js непосредственно из DOM, а кроме того, по-новому писать нативные приложения со всеми веб-технологиями. Вот некоторые ключевые особенности:

  • Приложения, написанные на современных HTML5, CSS3, JS и WebGL.
  • Полная поддержка API Node.js и всех его сторонних модулей.
  • Хорошая производительность: Node и WebKit работают в одном потоке.
  • Простота создания пакета и распространения приложений.
  • NW.js доступна на Linux, Mac OS X и Windows.

fullPage.js


fullPage.js от Альваро Триго простая и удобная в использовании библиотека, позволяющая создавать одностраничные приложения и альбомные слайдеры. Она доступна для Vue, React и Angular и полностью отзывчива для мобильных устройств. Несколько замечательных примеров можно найти здесь. Библиотека бесплатна для использования в проектах с открытым исходным кодом. Однако, если вы хотите использовать его в коммерческой среде, вам придётся купить лицензию. Библиотека выглядит действительно круто, так что посмотрите на неё! Я надеюсь, что вы сможете использовать некоторые из этих репозиториев для своих проектов или других целей.

image



Подробнее..

Перевод Крупные компании, использующие Node.js

13.04.2021 12:15:42 | Автор: admin


Node.js это серверная среда выполнения JavaScript, исполняющая код вне браузера. Эта технология идеально подходит для многих веб-сайтов, специализирующихся на стриминге, играх, тайм-трекерах, приложениях соцсетей и т.п. Она обеспечивает масштабируемое и быстрое решение для приложений реального времени.

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

Действительно ли Node.js меняет рынок?


Согласно данным Stack Overflow, Node.js абсолютный лидер в мире технологий, занимающий 50,4% рынка. Почему же он стал столь популярным?

Согласно последнему отчёту Node.js, эта технология оказывает на бизнес значительное влияние: она обеспечивает рост продуктивности разработчиков на 68%, на 48% повышает производительность приложений, и на 13% качество обслуживания клиентов. Более того, похоже, что эти значения со временем растут:

image

Кроме того, в отчёте Node.js упоминается, что четверо из пяти бэкенд- и фулл-стек-разработчиков используют фреймворки Node.js. Почему разработчики выбирают Node.js?

Во-первых, с этой средой выполнения JavaScript легко работать, и она обеспечивает выполнение кода на стороне сервера. Во-вторых, она обеспечивает высокую масштабируемость, а также ускоряет циклы разработки. В-третьих, это одна из лучших технологий с развитым сообществом open source. О преимуществах Node.js можно узнать от специалистов.

Десять известных компаний, использующих Node.js для бэкенда


Учитывая длинный список преимуществ применения Node.js, легко поверить, что среди крупнейших компаний, использующих эту технологию, есть такие как НАСА, Uber и Twitter. Кто пользуется Node.js, почему они решили перейти на Node.js и чем это для них обернулось?

Netflix


Netflix крупнейший поставщик потокового контента и видео с 93 миллионами пользователей по всему миру. Его путь к современному успеху начался в 2015 году, когда используемая в качестве бэкенд-технологии Java больше не могла справляться с такой быстрорастущей базой пользователей. Бэкенд-разработка не поспевала за фронтендом, что влекло за собой увеличение времени загрузки. Невозможно было реализовать настраиваемый дизайн UI, что снижало качество обслуживания клиентов. Кроме того, на сборку Java тратилось слишком много времени, поэтому процессы разработки и развёртывания были неэффективно медленными.

Преимущества, полученные Netflix:

  • После перехода на технологию Node.js время запуска снизилось на 70%. Раньше загрузка интерфейса Netflix занимала до десяти секунд, а теперь всего секунду;
  • Node.js упростил интеграцию микросервисов и разбиение огромного блока информации на подробный интерфейс;
  • Переход от бэкенда к фронтенду был значительно ускорен, поскольку среда Node.js основана на JavaScript.

НАСА


НАСА одна из самых известных в мире организаций. НАСА решила перейти на Node.js после инцидента, едва не повлёкшего фатальные последствия. Причиной инцидента стало долгое время доступа из-за неэффективного хранения данных между несколькими точками. Разработчики НАСА посчитали, что важно переместить данные в облачную базу данных для снижения времени доступа. Кроме того, большинство приложений НАСА было написано на JavaScript.

Преимущества для НАСА:

  • Время доступа снизилось на 300%, что позволило пользователям получать информацию за секунды, а не за часы;
  • НАСА успешно перенесла старые базы данных в облако и обеспечила доступ к ним через API;
  • Node.js сократил процесс работы с базами данных с 28 шагов всего до семи, что значительно упростило научные исследования.

Trello


Trello это инструмент для управления проектами, используемый во множестве отраслей и стран. Подобная платформа требует мгновенных обновлений в реальном времени и без задержек, и именно поэтому Trello стала одной из компаний, использующих Node.js на стороне сервера. Trello необходимо жонглировать несколькими подключениями к серверу в реальном времени, чтобы обновления передавались бесперебойно и вовремя.

Основные преимущества для Trello:

  • Node.js предоставил возможность создания чрезвычайно облегчённого одностраничного приложения;
  • Благодаря Node.js Trello может обрабатывать обновления с нулевыми задержками;
  • Архитектура Node.js позволила сократить затраты на разработку и прототипирование.

Переход компании PayPal на Node.js


Система PayPal, имеющая более 200 миллионов активных аккаунтов, является мировым лидером отрасли онлайн-платежей и переводов. В 2013 году компания столкнулась со сложностями, вызванными Java, которые плохо сочетались с фронтенд-разработкой. Java обеспечивала длительное время разработки, а также низкую производительность, поэтому PayPal стала одной из компаний, использующих Node.js.

Полученные PayPal результаты:

  • Меньшая по размерам команда разработчиков создала приложение Node.js за более короткое время;
  • Снизилось время отклика, что привело к уменьшению времени загрузки на 35%;
  • После внедрения технологии Node.js количество пользовательских запросов в секунду удвоилось.

LinkedIn


Ещё одна компания, использующая Node.js это LinkedIn, крупнейшая социальная платформа для бизнеса и трудоустройства. Её популярность продолжает расти, а база составляет 467 миллионов пользователей из более чем 200 стран. После перехода с Ruby on Rails на Node.js компания создала приложение, работающее в десять раз быстрее старой версии. Решение было принято из-за синхронизации приложения на Ruby, которая приводила к повышению времени загрузки, особенно при увеличении объёма трафика.

Полученные LinkedIn преимущества:

  • Вся архитектура LinkedIn создавалась на JavaScript, что упростило обработку клиент-серверных взаимодействий;
  • Количество серверов сократили с тридцати до трёх, что удвоило пропускную способность по трафику.

Опыт Uber с Node.js


Uber ещё одна активно развивающаяся компания, каждые полгода расширяющая пользовательскую базу и работающая в 68 странах. Из-за постоянно растущего количества подключений Uber пришлось создавать архитектуру реального времени. Кроме того, компания проводила сложный анализ хранящихся на платформе данных, для которого требовалась бесперебойная производительность сервисов. Именно поэтому теперь Uber стала одной из тех компаний, которые используют Node.js в продакшене.

Полученные Uber выгоды:

  • Node.js позволил Uber намного быстрее обрабатывать огромный объём данных и многочисленные запросы пользователей;
  • Благодаря технологии Node.js компания Uber способна ежедневно обслуживать 14 миллионов поездок;
  • Uber повысила связность системы и снизила затраты на управление, создав более 600 конечных точек без сохранения состояния.

Переход на Node.js пример Twitter


Более 80% владельцев аккаунтов Twitter получают к ним доступ через смартфон, поэтому компания приняла решение о создании Twitter Lite приложения с минимальными функциями, способного работать даже при плохом Интернет-соединении. Кроме того, веб-сайтная версия Twitter не была оптимизирована под плохие условия соединения. Всё это привело к тому, что Twitter стала одной из компаний, использующих Node.js.

Преимущества для Twitter:

  • Twitter Lite занимает мало места от 1% до 3% памяти телефона, что удобно для пользователей мобильных устройств;
  • Приложение работает даже с подключениями 3G и 2G;
  • Затраты на поддержку Twitter Lite значительно ниже, чем у Twitter Desktop.

eBay


Ещё одним бизнесом, использующим Node.js, является eBay. Имеющий 183 миллионов пользователей eBay это крупнейшая торговая площадка, предоставляющая услуги онлайн-продаж C2C и B2C. Раньше приложение eBay работало на Java, что приводило к долгой загрузке и низкой производительности. Так как eBay это платформа с огромным объёмом трафика, ей требовалась технология, которая бы ускорила разработку, чтобы она поспевала за изменениями во фронтенде.

Выгода для eBay:

  • eBay создала при помощи Node.js микросервисы, которые выполняются в реальном времени и не перегружают инфраструктуру.
  • Node.js обеспечил масштабируемость, скорость и масштабируемость.

Groupon


Groupon крупнейшая площадка, на которой представлены купоны, скидки и выгодные предложения, она имеет базу в 40 миллионов пользователей. Когда в 2019 году Groupon достиг отметки в 200 миллионов скачиваний, то столкнулся с проблемами масштабируемости. Именно тогда компания обратила внимание на Node.js и провела крупнейшее в мире развёртывание продукта на Node.js.

Преимущества, полученные Groupon:

  • Развёртывание Node.js обеспечило высокую масштабируемость, что позволило реализовать бесперебойную работу 3400 бэкенд-сервисов;
  • Скорость загрузки удвоилась;
  • Node.js упростил и ускорил миграцию на другую платформу.

Medium


Medium это известная платформа для онлайн-публикаций с 85 миллионами пользователей, использующая Node.js. Достигнув в 2016 году планки в 7,5 миллионов постов, команда Medium ощутила потребность в управлении big data без превышения нагрузки на сервера. Кроме того, компании нужно было соответствовать постоянно растущим требованиям текстовых редакторов к публикации постов.

Преимущества для Medium:

  • Даже страницы с большими изображениями и объёмным контентом грузятся за 2,7 секунды.
  • Node.js повысил качество обслуживания пользователей и ускорил время развёртывания.

TechMagic


TechMagic это компания, специализирующаяся в разработке ПО. Мы создаём приложения с нуля и внедряем своих специалистов в команды разработки стартапов, используем различные технологии фулл-стека, в том числе и Node.js.

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

Elements.cloud это компания, помогающая другим бизнесам в визуализации и организации бизнес-процессов. Самой большой сложностью для Elements.cloud стала реализация инструментов настраиваемой привязки процессов и визуализации на фоне автоматизированной масштабируемости инфраструктуры бэкенда. TechMagic помогла Elements.cloud в создании высокомасштабируемого и экономичного приложения на основе инфраструктуры Node.js и AWS.

Заключение


Если вы всё ещё не уверены в том, что Node.js это технология будущего, перечислю других крупных игроков, использующих её в своей работе: Google, Yahoo, Mozilla, Microsoft и многие другие. Благодаря её неограниченным возможностям всё больше компаний внедряет технологию Node.js. Однажды эта набирающая обороты технология завоюет рынок и станет лучшим фреймворком для каждой компании, от стартапов до крупных компаний. Если у вас есть задумка какого-то продукта, то подумайте над использованием Node.js в качестве его бэкенда.



На правах рекламы


Мощные виртуальные серверы с процессорами AMD EPYC для разработчиков. Частота ядра CPU до 3.4 GHz. Максимальная конфигурация позволит оторваться на полную 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe.

Подробнее..

Перевод Думать, как фронтенд-разработчик

07.12.2020 20:14:08 | Автор: admin
Привет Хабр! У нас стартанул новый поток курса Frontend-разработчик, а я делюсь с вами небольшим чек-листом для фронтендера о том, как мыслить при создании макета, какие вопросы задавать себе самому. Смело кладите её в закладки, если хотите рассказать своему падавану джуну, с какой стороны подойти к дизайну макета, но не хотите тратить своё время на объяснение относительно несложных вещей.




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

Детали в сторону


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



В этой конструкции мы имеем следующее:

  • Заголовок/Навигация.
  • Главная секция.
  • Как это работает.

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



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

  • Заголовок во всю ширину: похоже, что заголовок занимает всю ширину видового экрана и его содержимое внутри обёртки не ограничено.
  • Содержимое элемента hero центрируется горизонтально, и обратите внимание, что для него нужно установить max-width (у абзаца две строки).
  • Как это работает: это макет из 4 колонок, раздел в целом ограничен обёрткой.

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

<header></header><section class="hero">  <!-- A div to constraint the content -->  <div class="hero__content"></div></section><div class="wrapper">  <!-- 4-columns layout -->  <section class="grid-4"></section></div>

Поскольку у нас есть раздел из 4 столбцов, для него я воспользуюсь CSS-сеткой (grid). Это идеальный вариант применения для неё.

.wrapper {  margin-left: auto;  margin-right: auto;  padding-left: 1rem;  padding-right: 1rem;  max-width: 1140px;}.hero__content {  max-width: 700px;  margin-left: auto;  margin-right: auto;}.grid-4 {  display: grid;  grid-template-columns: repeat(4, 1fr);}

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

Страница статьи


В этом примере у нас есть макет страницы статьи. Вот пользовательский интерфейс, который содержит:

  • Заголовок.
  • Заголовок страницы.
  • Предпросмотр изображения для статьи.
  • Содержание статьи.
  • Боковую панель (справа).



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



Вот они:

  • Заголовок сайта, занимающий всю ширину страницы.
  • Заголовок страницы, содержащий заголовок статьи и её описание, содержимое выровнено по левому краю с помощью max-width.
  • Макет из двух колонок, содержащий основной (main) и боковой (sidebar) элементы.
  • Внутреннее содержание статьи, которая центрирована горизонтально и имеет max-width.

Заголовок страницы статьи




Здесь нет необходимости применять какой-то метод компоновки. Простой max-width сделает свою работу. Обязательно добавьте горизонтальный внутренний отступ (padding), чтобы края элемента не прилипали к краям на небольших видовых экранах.

.page-header {  max-width: 50rem;  padding: 2rem 1rem;}

Статья основа и сайдбар




Основной элемент (main) статьи занимает всю ширину видового экрана за вычетом ширины боковой панели. Обычно боковая панель должна иметь фиксированную ширину. Для этого идеально подходит CSS-сетка (grid).

.page-wrapper {  display: grid;  grid-template-columns: 1fr;}@media (min-width: 800px) {  grid-template-columns: 1fr 250px;}

Внутреннее содержание статьи должно ограничиваться внутри обёртки.

.inner-content {  max-width: 50rem;  margin-left: auto;  margin-right: auto;  padding-left: 1rem;  padding-right: 1rem;}

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

Погружение в детали


Как это работает


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



Колонки


  • Есть ли у нас случаи, когда число шагов может быть меньше или больше? Если да, как работать в такой ситуации?
  • Нужно ли, чтобы столбцы были равны по высоте, особенно когда на карточке очень длинный текст?

Заголовок


  • Нужно ли нам, чтобы раздел заголовка оставался в стороне? Или бывают случаи, когда он должна занимать всю ширину?

Адаптивный дизайн


  • В какой ситуации нужно складыванием адаптировать к размеру дочерние элементы раздела? Есть ли у нас какой-то триггер складывания? Если да, то что это за триггер?

Вот несколько возможных ситуаций с этим разделом. Что вы думаете? Как фронтенд-разработчик вы должны учитывать такие крайние случаи. Речь идёт не только о создании пользовательского интерфейса без учёта таких скрытых мелочей.



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

<div class="wrapper">  <section class="steps">    <div>      <h2>How it works</h2>      <p>Easy and simple steps</p>    </div>    <div class="layout">      <div class="layout__item">        <article class="card"></article>      </div>      <div class="layout__item">        <article class="card"></article>      </div>      <div class="layout__item">        <article class="card"></article>      </div>    </div>  </section>v</div>

.steps {  display: grid;  grid-template-columns: 1fr;  grid-gap: 1rem;}@media (min-width: 700px) {  .steps {    grid-template-columns: 250px 1fr;  }}.layout {  display: grid;  grid-template-columns: 1fr;  grid-gap: 1rem;}@media (min-width: 200px) {  .layout {    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));  }}

Я воспользовался CSS-сеткой с minmax() и ключевым словом auto-fit. Это полезно, когда количество карт может увеличиваться или уменьшаться. Смотрите видео ниже:



Раздел hero


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



Изображение раздела


  • Как изображение должно представляться? Это изображение меняется каждый день, или оно должно обновляться с помощью CMS?
  • Должны ли мы использовать HTML или фон в CSS?
  • Каково ожидаемое соотношение сторон изображения?
  • Нужно ли использовать несколько размеров изображения в зависимости от размера видового экрана?
  • Может быть, у нас не изображение, а видео? У меня бывали ситуации, когда после работы над изображением клиенты говорили, что вместо изображения нужно видео.

Высота раздела


  • Какова минимальная высота раздела?

Длина контента


  • Нужно ли устанавливать максимальную длину для заголовка и описания? Если да, то каковы минимум и максимум, с которыми дизайн должен работать?

Расстояние между элементами


  • Как обрабатывать вертикальное расстояние?

Центрирование контента


  • Как центрировать контент по горизонтали и по вертикали? С учётом того, что известна только ширина, но не высота.

Ограничение контента


  • Ради повышения читабельности контент лучше ограничивать. Какова идеальная ширина ограничения?

Адаптивный дизайн


  • Нужно ли менять размер шрифта в зависимости от ширины видового экрана? Если да, то что лучше использовать: пиксели px, единицы видового экрана или функцию CSS clamp()?

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

В нашем компоненте я займусь расстоянием между дочерними элементами. Для этой задачи мне нравится пользоваться свойством flow-space. Я узнал о нём из блога Piccalil Энди Белла. Наша задача предоставить расстояние между напрямую родственными элементами:



<section class="hero">  <!-- A div to constraint the content -->  <div class="hero__content flow">    <h2>Food is amazing</h2>    <p>Learn how to cook amazing meals with easy and simple to follow steps</p>    <a href="http://personeltest.ru/aways/habr.com/learn">Learn now</a>  </div></section>

.flow > * + * {  margin-top: var(--flow-space, 1em);}

И последнее


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

image



Рекомендуемые статьи


Подробнее..

Перевод Разрушаем мифы о производительности Android

18.12.2020 18:13:39 | Автор: admin

Узнайте, какие мифы о производительности Android выдержали испытание бенчмарком

В преддверии старта курса "Android Developer. Basic" приглашаем всех желающих посмотреть открытый урок по теме "Unit-тестирование в Android".

А также делимся переводом полезного материала.


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

В этой статье мы собираемся проверить эти мифы на прочность в духе MythBusters (Разрушители легенд). Для развенчания мифов мы используем реальные примеры и инструменты, которые вы тоже можете использовать. Мы ориентируемся на превалирующие шаблоны использования: то, что вы, как разработчики, вероятнее всего, делаете в своем приложении. Но стоит озвучить одно предостережение: помните, что очень важно сначала производить измерения, прежде чем принимать решение об использовании той или иной практики по соображениям производительности. Тем не менее, давайте приступим к разрушению мифов!

Миф 1: Приложения на Kotlin больше и медленнее, чем приложения на Java

Команда Google Drive перенесла свое приложение с Java на Kotlin. Этот перенос затронул более 16 000 строк кода и 170 файлов, охватывающих более 40 таргетов сборки. Среди показателей, которые отслеживала команда, одним из важнейших было время запуска.

Как видите, переход на Kotlin не возымел существенного влияния.

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

С другой стороны, команда добилась сокращения количества строк кода на 25%. Их код стал чище, понятнее и проще в обслуживании.

Следует отметить одну вещь касательно Kotlin: вы можете и должны использовать инструменты сжатия кода, такие как R8, в котором даже есть специальные оптимизации для Kotlin.

Миф 2: Геттеры и сеттеры обходятся дорого

Некоторые разработчики из соображений производительности предпочитают использовать public поля вместо сеттеров и геттеров. Распространенный шаблон кода, где getFoo служит в качестве геттера, выглядит примерно так:

public class ToyClass {   public int foo;   public int getFoo() { return foo; }}ToyClass tc = new ToyClass();

Мы сравнили это с использованием public поля tc.foo, когда код нарушает инкапсуляцию объекта для прямого доступа к полям.

Мы протестировали это с помощью библиотеки Jetpack Benchmark на Pixel 3 с Android 10. Библиотека бенчмарков предоставляет фантастический способ легко протестировать ваш код. Среди особенностей библиотеки - то, что она предварительно разгоняет код, поэтому результаты представляют собой стабильные показатели.

Так что же показали бенчмарки?

Версия с геттером работает так же хорошо, как и версия, с прямым доступом к полю. Этот результат неудивителен, поскольку среда выполнения Android (ART) инлайнит в ваш код все тривиальные методы доступа. Таким образом, код, выполняемый после компиляции JIT или AOT, одинаков. Даже больше, когда вы обращаетесь к полю в Kotlin в этом примере tc.foo вы обращаетесь к этому значению с помощью геттера или сеттера в зависимости от контекста. Однако, поскольку мы инлайним все методы доступа, ART выручит нас: разницы в производительности нет.

Если вы не используете Kotlin и если только у вас нет веской причины сделать поля public, вам не следует ломать хорошие практики инкапсуляции. Скрывать private данные вашего класса хорошая идея, и вам не следует изобличать их только по соображениям производительности. Используйте геттеры и сеттеры.

Миф 3: Лямбда-выражения медленнее, чем внутренние классы

Лямбда-выражения, особенно с введением потоковых API, представляют собой удобную языковую конструкцию, которая обеспечивает очень компактный код.

Возьмем код, в котором мы суммируем значения некоторых внутренних полей из массива объектов. Сначала используя потоковые API с операцией map-reduce.

ArrayList<ToyClass> array = build();int sum = array.stream().map(tc -> tc.foo).reduce(0, (a, b) -> a + b);

Здесь первая лямбда преобразует объект в целое число, а вторая суммирует два полученных значения.

Это можно сравнить с определением эквивалентных классов для лямбда-выражений.

ToyClassToInteger toyClassToInteger = new ToyClassToInteger();SumOp sumOp = new SumOp();int sum = array.stream().map(toyClassToInteger).reduce(0, sumOp);

Есть два вложенных класса: один - это toyClassToInteger, который преобразует объекты в целое число, а второй - это операция суммирования sum.

Очевидно, что первый пример, с лямбдами, гораздо более элегантен: большинству рецензентов кода, скорее всего, придется по душе именно он.

Однако что насчет различий в производительности? Мы снова использовали библиотеку Jetpack Benchmark на Pixel 3 с Android 10 и не обнаружили разницы в производительности.

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

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

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

Миф 4: Аллоцирование объектов дорогое удовольствие, лучше использовать пулы

Android использует самые современные функции выделения памяти и сборки мусора. Аллоцирование объектов улучшалось почти в каждом релизе, как можно увидеть на следующем графике.

Сборка мусора также значительно улучшилась от релиза к релизу. Сегодня сборка мусора не влияет на сбои или плавность работы приложения. На следующем графике показано улучшение, которое мы сделали в Android 10 для сбора объектов с коротким жизненным циклом с параллельным Gen-CC. Улучшения, которые также заметны в новом релизе Android 11.

Пропускная способность существенно выросла в бенчмарках сборки мусора, таких как H2, более чем на 170%, а в реальных приложениях, таких как Google Sheets, на 68%.

Так как же это влияет на решения в написании, например, аллоцировать ли объекты с помощью пулов?

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

Pool<A> pool[] = new Pool<>[50];void foo() {   A a = pool.acquire();      pool.release(a);}

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

Чтобы проверить это, мы реализовали микробенчмарк для измерения двух вещей: накладных расходов на стандартную аллокацию и извлечения объекта из пула и накладных расходов ЦП, чтобы выяснить, влияет ли сборка мусора на производительность приложения.

Для этого сценария мы использовали Pixel 2 XL с Android 10, выполняя код аллокации тысячи раз в очень жестком цикле. Мы также смоделировали объекты разных размеров, путем добавления дополнительных полей, потому что производительность может быть разной для маленьких и больших объектов.

Вот результаты накладных расходов на аллокацию объектов:

Вот результаты накладных расходов ЦП на сборку мусора:

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

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

Итак, разрушен ли этот миф? Не совсем. То, будут ли пулы объектов более эффективными, зависит от потребностей вашего приложения. Во-первых, помимо сложности кода, помните о других недостатках использования пулов:

  • Может иметь более высокий объем памяти.

  • Риск сохранения объектов в живых дольше, чем необходимо.

  • Требуется очень эффективная реализация пула

Однако подход с использованием пула может быть полезен для больших или дорогостоящих в аллоцировании объектов.

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

Миф 5: Профилирование моего отлаживаемого приложения это хорошая идея

Профилирование вашего приложения, пока оно является отлаживаемым (debuggable), было бы действительно удобно, ведь, в конце концов, обычно вы пишете код в режиме отладки. И даже если профилирование в отлаживаемом режиме немного неточно, возможность выполнять итерацию быстрее должна компенсировать это. К сожалению, нет.

Чтобы проверить этот миф, мы рассмотрели несколько бенчмарков для общих рабочих процессов. Результаты представлены на следующем графике.

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

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

Странные дела

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

Странность 1: Multidex: влияет ли это на производительность моего приложения?

APK-файлы становятся все больше и больше. Они не вписываются в ограничения традиционной спецификации dex уже какое-то время. Multidex это решение, которое вы должны использовать, если ваш код превышает ограничение на количество методов.

Вопрос в том, сколько методов - это слишком много? И есть ли влияние на производительность, если приложение имеет большое количество dex-файлов? Может быть даже не из-за того, что ваше приложение слишком велико, вы можете просто разделить dex-файлы dex на основе функций для упрощения разработки.

Чтобы исследовать влияние множества dex-файлов на производительность, мы взяли калькулятор. По умолчанию это приложение с одним dex-файлом. Затем мы разбили его на пять dex-файлов на основе границ его пакета, чтобы имитировать разбиение по функциям.

Затем мы протестировали несколько аспектов производительности, начиная со времени запуска.

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

А как насчет размера APK и памяти?

Как видите, немного увеличился и размер APK, и объем памяти во время работы приложения. Это связано с тем, что, когда вы разделяете приложение на несколько dex-файлов, каждый dex-файл содержит некоторые дублированные данные для таблиц символов и кешей.

Однако вы можете минимизировать этот прирост, уменьшив зависимости между dex-файлами. В нашем случае мы не пытались его минимизировать. Если бы мы попытались минимизировать зависимости, мы бы обратились к инструментам R8 и D8. Эти инструменты автоматизируют разделение dex-файлов, помогают избежать распространенных ошибок и минимизировать зависимости. Например, эти инструменты не создадут больше dex-файлов, чем необходимо, и не поместят все startup-классы в основной файл. Однако, если вы делаете разбиение dex-файлов самостоятельно, всегда измеряйте то, что вы разбиваете.

Странность 2: Мертвый код

Одно из преимуществ использования среды выполнения с JIT-компилятором, например ART, заключается в том, что среда выполнения может профилировать код, а затем оптимизировать его. Существует теория, что если код не профилируется интерпретатором/JIT-системой, он, вероятно, также не выполняется. Чтобы проверить эту теорию, мы исследовали профили ART, созданные приложением Google. Мы обнаружили, что значительная часть кода приложения не профилируется ART интерпретатором JIT-системы. Это показатель того, что большая часть кода на самом деле никогда не будет выполняться на устройствах.

Есть несколько типов кода, которые не могут быть профилированы:

  • Код обработки ошибок, который, надеюсь, выполняется нечасто.

  • Код для обратной совместимости, код, который не выполняется на всех устройствах, особенно на устройствах с Android 5 или более поздней версией.

  • Код для редко используемых функций.

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

Быстрый, простой и бесплатный способ удалить ненужный код минимизировать его с помощью R8. Затем, если вы еще этого не сделали, преобразовать ваше приложение для использования Android App Bundle и Play Feature Delivery. Они позволяют улучшить взаимодействие с пользователем, устанавливая только те функции, которые используются.

Выводы

Мы развенчали ряд мифов о производительности Android, но также увидели, что в некоторых случаях все не однозначно. Поэтому очень важно проводить сравнительный анализ и измерения, прежде чем выбирать сложные или даже небольшие оптимизации, которые противоречат хорошим практикам написания кода.

Существует множество инструментов, которые помогут вам измерить и решить, что лучше всего подходит для вашего приложения. Например, в Android Studio есть профилировщики для нативного и неродного кода, в нем даже есть профилировщики для использования батареи и сети. Есть инструменты, которые могут копнуть глубже, например Perfetto и Systrace. Эти инструменты могут предоставить очень подробное представление о том, что происходит, например, во время запуска приложения или сегмента вашего выполнения.

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

Java является зарегистрированным товарным знаком Oracle и/или ее дочерних компаний.


Узнать подробнее о курсе "Android Developer. Basic".

Посмотреть открытый урок по теме "Unit-тестирование в Android".

ЗАБРАТЬ СКИДКУ

Подробнее..

Пять причин, по которым следует использовать Apache Wicket

01.01.2021 20:09:47 | Автор: admin

Apache Wicket - это фреймворк для веб-разработки на Java. Я чувствую, что ему не уделяют столько внимания, сколько он того заслуживает. Я профессионально использую Wicket для реальных проектов последние 6 лет и мне это нравится! В этом посте давайте рассмотрим пять причин, по которым вам стоит подумать об его использовании.

1. Простое управление состоянием

Опыт разработки приложений Wicket очень похож на разработку для настольных компьютеров. Иногда вы можете почти забыть о том, чтоб вы работаете с HTTP, т.к. нет необходимости сохранять состояния. Это связано с тем, что в Wicket веб-страница и все ее компоненты (кнопки, текстовые поля и т. д.) Являются объектами Java, которые поддерживают свое собственное состояние. Состояние компонентов сериализуется в сеансе пользователя и десериализуется в нужное время.

Проще говоря, предположим, что у вас есть форма с полями, которые пользователь заполняет и отправляет. В приложении Wicket эта форма, ее поля и кнопка отправки являются компонентами (объектами Java), которые создаются и добавляются на веб-страницу. При нажатии кнопки отправки:

1.У нас автоматически есть доступ к вводу пользователя, обычно в виде полей POJO.

2.Нам не нужно связывать запрос HTTP POST с запросом GET.

Нам также не нужно думать о заполнении полей формы отправленными значениями. Это делается с помощью моделей, которые являются основной концепцией Wicket.

2. Стандартная интеграция HTML

HTML в Wicket не требует каких-либо специальных тегов, в отличие от некоторых других фреймворков. Фактически, вы можете взять любой существующий HTML и интегрировать его с вашим приложением Wicket практически без изменений. Для подключения HTML-тегов к компонентам Wicket необходим только один атрибут: wicket: id Рассмотрим пример:

<div wicket:id="userName">Roman</div>add(new Label("userName", getUsername()));

wicket:id "userName" используется для подключения HTML элемента с компонентом Wicket. Компонент Wicket Label получит имя пользователя и отобразит div тег . Ничего страшного, если сейчас это не совсем понятно. Это становится привычным и интуитивно понятным, когда вы начинаете экспериментировать с ним. Компоненты Wicket являются объектами первого класса и могут инкапсулировать собственную разметку HTML / CSS / JS, как в некоторых популярных фреймворках, таких как React. Это позволяет нам создавать код, который можно многократно использовать.

3. Не требуется Javascript (по большей части)

В какой-то момент вы закончите писать код JS. Поддержка AJAX, предоставляемая Wicket, означает, что вам не нужно писать собственный JS-код для наиболее распространенных задач. За кулисами Wicket использует JQuery и автоматически генерирует JS-код на веб-странице. Давайте рассмотрим для примера страницу с раскрывающимся списком и различными другими компонентами, которые зависят от выбора этого раскрывающегося списка. Когда выбор изменяется, нам нужно обновить эти различные другие компоненты на странице. На самом деле для этого не требуется код Javascript . Это делает Wicket идеальным решением для создания сложных интерфейсов со сложной бизнес-логикой.

4. Система событий / сообщений

События Wicket - это способ взаимодействия компонентов и страниц между собой. Используя эту функцию, мы можем создавать очень сложные, но не связанные друг с другом структуры компонентов. Компонент может транслировать сообщение, не зная, кто его получит. Когда компонент заинтересован в конкретном типе сообщения, он может просто подписаться, чтобы получать уведомление, когда это сообщение будет транслироваться. Компонент может транслировать событие критического обновления с полезной нагрузкой всем другим компонентам на странице следующим образом:

send(getPage(), Broadcast.BREADTH, new CriticalUpdate(target, payload));

И если какой-то компонент заинтересован в получении CriticalUpdate , он будет регистрироваться следующим образом:

public void onEvent(IEvent event) {    if (event.getPayload() instanceof CriticalUpdate) {       String msg = ((CriticalUpdate)event.getPayload());       //do something with the msg      } }

5. Модульное тестирование

Компонентный / сохраняющий состояние характер Wicket означает, что мы можем писать модульные тесты для внешнего интерфейса так же, как мы пишем их для уровня сервиса или нашего уровня доступа к данным. Wicket предоставляет полезные утилиты, упрощающие написание модульных тестов. Давайте рассмотрим пример простого сценария, который может оказаться не таким простым для тестирования в других средах. У нас есть веб-страница с интерфейсом CRUD: таблица с именами и кнопками удаления. Форма с текстовым полем и кнопкой для добавления новых строк в таблицу. Мы можем написать тест, который отобразит страницу, имитирует заполнение и отправку формы пользователем, обеспечит правильное обновление таблицы, имитирует нажатие кнопки удаления пользователем и так далее. Все это может быть выполнено с использованием чистого кода Java и JUnit, не прибегая к Selenium, Puppeteer или аналогичным библиотекам.

Заключение

Надеюсь, вы услышали достаточно, чтобы попробовать Wicket. Если вам интересно узнать больше:

  1. Перейдите на официальный сайт, где есть отличная документация.

  2. Взгляните на примеры кода часто встречающихся практик в веб-разработке.

Подробнее..

Перевод Как понять свойство clip-path в CSS

29.01.2021 14:10:10 | Автор: admin
В те далёкие времена, когда я впервые столкнулся со свойством CSS clip-path, мне потребовалось больше времени, чем я ожидал, и я изо всех сил старался запомнить, как работает свойство. Не знаю точно, почему так получилось, но, может быть, потому, что я не пользовался им часто? Во всяком случае, я изучу его снова вместе с вами. В этой статье я стремлюсь дать чёткое, детальное объяснение того, как работает clip-path, когда его использовать и как вы можете воспользоваться им в своих проектах веб-разработки. Вы готовы?



Вступление


Свойство clip-path создаёт область отсечения: внутри неё контент видно, а вне её нет. Вот простой пример круга с применением clip-path.

.card {  background-color: #77cce9;  clip-path: circle(80px at 50% 50%);}


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


Система координат


Прежде чем углубляться в детали clip-path, стоит упомянуть о том, как работает система координат. Начало координат это верхний левый угол, ось x направлена вправо, а ось y вниз.

Учитывая это, чтобы увидеть, как обрезается элемент, давайте возьмём простой пример. В нём обрезанная область это круг размером 100 px, его центр расположен в точке 0,0 (вверху слева).


Обратите внимание, что пользователь видит только выделенную тёмно синюю область. Оставшаяся часть круга обрезана. Вопрос в том, как сделать видимым весь круг? Для этого нужно изменить точки осей x и y.


Центр круга расположен в 100 px левее и 100 px выше. Теперь, когда вы понимаете, как работает система координат, я расскажу о возможных значениях свойства clip-path.

Значения clip-path


inset


Значение inset определяет вставляемый прямоугольник. Мы можем контролировать четыре края, точно так же, как это делается с краями или отступом. В примере ниже .card имеет свойство inset 20px со всех краёв (сверху, справа, снизу и слева).

.card {  clip-path: inset(20px);}

Если нужно, подправьте inset с одного из краёв. Вот пример, как это сделать:

.card { clip-path: inset(20 px 20 px 50 px 20 px);}


Выше класс .card имеет свойство inset со значением 50px снизу.

Вопрос в том, возможна ли округлая вставка? Да! Благодаря ключевому слову round. Добавление ключевого слова слева от радиуса округляет углы, вот так: round <border-radius>.

.card {  clip-path: inset(20px 20px 50px round 15px);}


Кроме того, мы даже можем настроить радиус каждой стороны отдельно. Вот пример с нулевым радиусом верхнего правого и нижнего левого углов.
.card {  clip-path: inset(20px 20px 50px round 15px 0);}

circle()


Чтобы использовать значение circle(), нам понадобится радиус и его положение. Вот пример:

.card {  clip-path: circle(80px at 50% 50%);}

Радиус окружности равен 80px, и она позиционирована так: 50% на оси x, 50% на оси y.

ellipse()


С помощью функции ellipse() мы можем установить ширину и высоту, чтобы сделать отсечение овальным.

.card {  clip-path: ellipse(100px 80px at center);}


polygon()


Самое интересное для меня значение polygon(). Можно управлять несколькими наборами значений по осям x и y.

.card {  clip-path: polygon(x y, x y, x y, x y);}

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

.card {  clip-path: polygon(5% 5%, 95% 5%, 95% 95%, 5% 95%);}


Используя значение polygon(), можно рисовать сложные фигуры с несколькими точками.

path()


Значение path() позволяет использовать элемент SVG, чтобы обрезать определённую область. Сейчас его поддержка браузером непоследовательна. Чтобы заставить это свойство работать в разных браузерах, нам нужно использовать встроенный SVG, а затем функцию url() как значение для clip-path.

<svg class="svg">  <clipPath id="triangle" clipPathUnits="objectBoundingBox">    <path d="M0.05,0.05 h1 v1"></path>  </clipPath></svg>

В коде CSS нужно добавить путь к clipPath при помощи url().

.card {  clip-path: url("#triangle");}


Теперь, когда мы рассмотрели теорию clip-path и возможные значения этого свойства, пришло время воспользоваться свойством по-настоящему и исследовать некоторые варианты его применения. Вы готовы?

Примеры применения


Эффект разворота плоскости


Так или иначе, нечто с подобной структурой вы уже видели. Это идеальный пример того, как использовать clip-path.
image

Можете ли вы предположить, как реализовать поворот? Здесь поможет polygon().

.section {  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%);}

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

.section {  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);}

Исследуем эту часть с помощью DevTools. Открыв Исследовать элемент, обратите внимание на маленький значок полигона в левой части значения polygon().


Нажав его, вы сможете отредактировать полигон в браузере. Посмотрите картинку ниже:



Угол относительно ширины видового экрана


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

.section {  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 5vw), 0 100%);}

Несколько углов


У меня в голове возник вопрос: захочется ли нам иметь несколько угловых секций? Посмотрите на рисунок ниже.


Первое, о чем я подумал, просто добавить box-shadow или border. К сожалению, они будут обрезаны, так что, даже если добавить их, мы не увидим того, что хотим увидеть. Решение в таком случае использовать несколько элементов, причём точка отсечения будет у каждого своя:

<div class="hero">  <img src="bg.jpg" alt="" /></div>

.hero {  position: relative;  min-height: 350px;}.hero img {  position: absolute;  left: 0;  top: 0;  width: 100%;  height: 100%;  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 90%);}.hero:after {  content: "";  position: absolute;  left: 0;  bottom: -20%;  z-index: -1;  width: 100%;  height: 100%;  background-color: #4545a0;  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 90%);}

У нас есть псевдоэлемент с тем же размером и clip-path, что и у другого элемента. Разница в том, что он расположен под ним с bottom:-20% и z-index:-1. Я написал значение 20%, потому что это то же, что 100 80.

Появление при прокрутке


Используя API IntersectionObserver, мы можем проявлять определённые элементы на странице во время прокрутки.

Значение inset


Самое полезное значение clip-path для этого эффекта inset. Почему? Посмотрите на рисунок ниже.


Обратите внимание, что синий прямоугольник может стать полностью невидимым, если написать inset(50%). Да, значение, которое сделает элемент невидимым, составляет 50%: мы применяем inset с четырёх сторон. Другими словами, inset применяется от края к центру прямоугольника. На рисунке ниже inset используется для показа изображений во время прокрутки:


Приведённый ниже код javascript добавляет класс is-visible к каждому изображению, которое находится в области просмотра. При этом мы можем увидеть изображение с помощью прокрутки.

const images = document.querySelectorAll("img");function check(entries) {  entries.map((entry) => {    if (entry.isIntersecting) {      entry.target.classList.add("is-visible");      observer.unobserve(entry.target);    }  });}const observer = new IntersectionObserver(check);images.forEach((image) => observer.observe(image));


img {  clip-path: inset(50%);  transition: 1.2s ease-in;}img.is-visible {  clip-path: inset(0);}

Всё просто. Мы создали простой эффект прокрутки с помощью нескольких строк CSS и JavaScript.


Кроме того, возможно контролировать направление перехода появления. Для этого нам нужно использовать одно из четырёх значений. Например, если нам нужен переход сверху вниз, нижнее значение должно быть изменено со 100% на 0. Посмотрите на картинку с объяснением:



А вот интерактивная демонстрация:


Эффекты наведения и анимации


clip-path это безграничные возможности, чтобы создавать анимации. Вот ещё один пример:


Что нам нужно сделать это добавить эффект наведения, который масштабируется из уже указанной позиции. Здесь давайте выберем значение circle().

Чтобы код поддерживался и читался проще, давайте воспользуемся переменными CSS. Так нам не нужно дублировать весь clip-path. Изменим только необходимые переменные CSS.

:root {  --pos: left center;  --size: 0;}.stats__item:before {  position: absolute;  left: 0;  top: 0;  width: 100%;  height: 100%;  background-color: #7777e9;  clip-path: circle(var(--size) at var(--pos));  transition: 0.4s linear;}.stats__item:hover:before {  --size: 300px;}

Посмотрите ниже как это работает.


Мало того, мы можем очень легко изменить положение анимации. Я создал интерактивную демонстрацию, где можно изменять позиции в выпадающем меню.


Если вам захотелось углубиться в эффекты анимации, мистер Адам Аргайл написал крайне полезную библиотеку анимации CSS, которая абсолютно полностью полагается на clip-path. Вот она.

Эффект пульсации


Эффект ряби обрёл популярность с релиза Material Design. С помощью clip-path этот эффект легко воспроизводится, вот так:


<button class="button"><span>Sign up now</span></button>

.button {  position: relative;}.button span {  position: relative;  z-index: 1;}.button:before {  content: "";  position: absolute;  left: 0;  top: 0;  width: 100%;  height: 100%;  background-color: #fff;  opacity: 0.1;  clip-path: circle(0 at center);  transition: 0.3s ease-out;}.button:hover:before {  clip-path: circle(100px at center);}



Полезно знать


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

Можно пользоваться относительными значениями.
Хочется привязать позицию clip-path к font-size? Это можно сделать! Воспользуйтесь единицами em или rem для clip-path и всё готово.

Ресурсы и связанные статьи



Я рад сообщить вам, что написал электронную книгу об отладке CSS. Если вам интересно, отправляйтесь на debuggingcss.com, чтобы прочитать бесплатный фрагмент. Если вам нравится мой контент, то вы можете поддержать меня, заплатив за мой кофе. Большое спасибо!



image



Подробнее..

Перевод Погружаемся в логические свойства CSS

13.03.2021 20:20:43 | Автор: admin

Поддержка логических свойств CSS со временем становится лучше. Однако мне по-прежнему трудно запомнить их, когда использую их в проекте. Что означают start и end? Несколько сложно охватить все детали без проб и ошибок.

В этой статье я нацелен прокачать вас и пробежаться по использованию логических свойств, чтобы возникло твёрдое понимание, у дизайнеров, говорящих на английском и арабском языках. Я попытался придумать визуальное объяснение логических свойств, которое, надеюсь, будет понятным. Готовы? Погружаемся!

Вступление

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

У нас есть карточка, содержащая аватар и текст. В макете слева направо поле расположено справа от аватара и наоборот, в макете слева направо поле отражено и расположено слева. Вот так это пишется без логических свойств:

.avatar {  margin-right: 1rem;}html[dir="rtl"] .avatar {  margin-right: 0;  margin-left: 1rem;}

Обратите внимание, что margin-rightв макете справа налево сброшено в 0, оно здесь не нужно. Представьте, что мы делаем это для большого проекта; кода слишком много. Но логические свойства решают проблему.

.avatar {  margin-inline-end: 1rem;}

Нам нужно только установить margin-inline-end, и свойство будет работать по-разному в зависимости от направления в HTML-документе. Мощно, правда?

Разница между inline и block

Используя логические свойства, вы обычно видите inline млм block. Давайте посмотрим, что они означают.

Смысл inlineи blockменяется исходя из режима письма. В языках вроде английского inlineнаправлен горизонтально, а block вертикально. В языках вроде японского всё наоборот: inlineнаправлено вертикально, block горизонтально.

Что означает inline?

В подобных английскому и арабскому языках inlineнаправлено горизонтально. В английском start указывает на левую (left) сторону в макетах слева направо (на английском языке) и он же указывает на правую (right) сторону в арабских макетах, которые справа налево. В макетах справа налево start указывает на правую сторону, end на левую.

В примере ниже круг имеет поле (margin) с правой стороны. В макетах справа налево поле должно быть слева. Запомните, что свойства start и end зависят от контекста направления макета:

Визуализация начала и конца

Начало и конец улицы

Чтобы прояснить, что же означают start и end, я покажу пример на картинке:

Мне нравится представлять это как начало и конец улицы. Когда направление слева направо, начало находится слева, а конец справа. Когда направление справа налево, всё наоборот.

Направление чтения

Другой способ запомнить принцип думать о направлении чтения. Английский текст начинается слева и заканчивается справа, арабский текст начинается справа и заканчивается слева.

Какие свойства можно применять как логические?

Большую часть свойств CSS можно применять как логические. Вот основные из них:

  • размеры: высота, ширина (height, width);

  • margin, border, padding, их подвиды;

  • обтекание (floating), позиционирование;

  • выравнивание текста.

Я не могу перечислить все логические свойства здесь: их много. Пожалуйста, прочитайте весь список на MDN.

Примеры и применение

Первый пример

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

У нас есть компонент со следующими свойствами:

  • left-padding и right-padding;

  • рамка (border) с левой стороны;

  • поле (margin) для иконки.

Вот так можно справиться с макетом слева направо.

.card {  padding-left: 2.5rem;  padding-right: 1rem;  border-left: 6px solid blue;}.card__icon {  margin-right: 1rem;}

А так с макетом справа налево; направления должны быть отражены.

html[dir="rtl"] .card {  padding-right: 2.5rem;  padding-left: 1rem;  border-left: 0;  border-right: 6px solid blue;}html[dir="rtl"] .card__icon {  margin-right: 1rem;}

И снова много работы. Но мы можем минимизировать CSS-код, вот так:

.card {  padding-inline-start: 2.5rem;  padding-inline-end: 1rem;  border-inline-start: 6px solid blue;}.card__icon {  margin-inline-end: 1rem;}

Второй пример: выравнивание текста

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

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

.indicator {  text-align: end;}

Вот как мы описали бы изложенное выше без логических свойств:

.indicator {  text-align: right;}html[dir="rtl"] .indicator {  text-align: left;}

Третий пример: позиционирование

Когда какой-то элемент позиционируется абсолютно, мы должны уделить внимание свойствам right и left:

.menu__toggle {  position: absolute;  right: 1rem;  top: 1rem;}html[dir="rtl"] .menu__toggle {  right: auto;  left: 1rem;}

Мы можем сократить код выше при помощи свойства inset Его поддержка не идеальна, но за ним будущее. Свойство inset-inline-endв макетах слева направо эквивалент правой стороны, а в макетах справа налево эквивалент левой стороны для макетов справа налево.Код выше можно написать так:

.menu__toggle {  position: absolute;  inset-inline-end: 1rem;  top: 1rem;}

Кроме того, top может выступать как inset-block-start, но это не нужно в нашем случае: мы не работаем с японским или с веб-сайтом на восточном языке.

Пример 4: float

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

img {  float: left;  shape-outside: circle(50%);  margin-right: 20px;}

Код работает в макетах слева направо, для направления справа налево код CSS будет вроде такого:

html[dir="rtl"] img {  float: right;  margin-right: 0;  margin-left: 20px;}

При помощи логических свойств код на CSS сокращается, вот так:

img {  float: inline-start;  shape-outside: circle(50%);  margin-inline-end: 20px;}

Намного проще, правда?

Логические по своей природе свойства

Grid и flexbox по умолчанию логические свойства. Это означает, что они отражают направление автоматически. При помощи этих свойств CSS-код сеток и компонентов для мультиязычных сайтов сокращается до минимума.

В следующем примере у нас grid-обёртка. Обратите внимание, что элементы упорядочены согласно направления.

Чего бы мне хотелось

Единственное моё желание на данный момент, чтобы свойство background-colorстало логическим.

Зачем? Чтобы добавить иконку как изображение фона так, чтобы она разворачивалась в зависимости от направления. К сожалению, свойства вроде background-position-inlineу нас нет. Вот, что я напишу сейчас.

.input {  background: url("mail.svg") left 0.5rem center/24px no-repeat;  padding-inline-start: 2.4rem;}html[dir="rtl"] {  background: url("icon.svg") right 0.5rem center/24px no-repeat;}

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

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

Другие профессии и курсы
Подробнее..

Как сделать хорошую интеграцию? Часть 1

29.12.2020 12:11:44 | Автор: admin
Вопрос в заголовке включает в себя неочевидную часть, ведь перед тем, как рассказывать про создание хорошей интеграции стоит определить, какую интеграцию мы считаем хорошей. А ответ на этот вопрос не однозначен.

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



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

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

Хорошая интеграция это интеграция с хорошей админкой


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

Однако, на практике дело обстоит совсем не так разработчики начинают с выбора технологической платформы и после этого упоенно пишут ядро. А админку делают по остаточному принципу, при этом ориентируясь на ситуацию, когда инциденты редки и уникальны. Конечно, этому есть причины. С одной стороны, разработчики верят в свой код, который (конечно) будет работать правильно и без ошибок. А, с другой стороны, заказчик хочет сократить стоимость, поэтому тоже верит разработчикам. Ну, или делает вид, что верит, при этом имея План Б жестко связать их SLA оперативного исправления инцидентов. Обычно такой план срабатывает плохо, и теряет от этого, конечно, бизнес. Потому что в ситуации, когда админка только показывает ошибку, но не позволяет с ней работать, служба поддержки обращается к разработчикам для разбора инцидентов. Те разбирают инциденты вручную долго и дорого, напрямую работая с базой данных или через технические средства для прямых обращений по http или другим протоколам.

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

Да и при тестировании очередное неудачное обновление с ошибкой запросто может породить вал из сотен или тысяч ошибок. Все таки тестовый контур не полноценно эмулирует реальный поток данных. Особенно, если этот поток новый и касается функционала, которого раньше не было. А ограничения целостности в сложном IT-ландшафте носят распределенный характер и изменения данных, допустимые в одной системе, могут оказаться неприемлемыми в другой, об этом мы отдельно поговорим в статье.

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

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

При обработке сообщений


Прием сообщений не должен полностью останавливаться на первой же ошибке


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

Необходимо контролировать последовательность обработки сообщений


Хотя в целом сообщения можно обрабатывать независимо, для для конкретной цепочки нарушение порядка часто чревато ошибками на системе-приемнике. При этом, сквозная нумерация всех сообщений и остановка всей интеграции из-за этого при первой же ошибке недопустимо, как я уже говорил. А во многих случаях простая последовательная нумерация невозможна, потому что отправка и прием сообщений часто выполняется многопоточно.

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

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

Надо уметь посмотреть сообщение, письмо или вызов, который будет выполняться


Я помню свой шок при работе с удаленными транзакциями Oracle в конце 90-х, когда выяснилось, что ошибочную транзакцию можно выполнить, но посмотреть ее содержание невозможно. Поэтому важно показать не только конверт сообщения, но и внутреннее его содержание в структурном виде, несмотря на обобщенный характер таких интерфейсов.

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

Надо уметь запустить сообщение на обработку в системе-получателе


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

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

Надо уметь найти сообщение в системе-источнике и повторно его отправить


Иногда сообщения теряются по дороге. Протокол http не гарантирует ни доставку сообщений, ни получение ответа. При этом повторная отправка при отсутствии ответа чревата дублированием сообщений ведь потерять могли именно ответ, а не само сообщение. Кроме того, цепочка передачи часто включает несколько этапов и получение ответа о доставки по всей цепочки не всегда просто. Аналогична ситуация и с другим транспортом. Поэтому при надежном транспорте предпочитают контролировать успешную постановку в очередь. Однако, если было выяснено, что сообщение пропущено и ожидаемые изменения не пришли, надо уметь найти сообщение в системе-источнике и повторно отправить:



Интерфейсы работы с инцидентами должны быть ориентированы на массовую обработку


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

При изменении объектов


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

  • Желательно видеть на интерфейсе те изменения, которые сообщение вносит в существующий объект. Идеально, когда мы можем видеть также изменения предыдущих сообщений (которые его меняли) и последующих необработанных (при их наличии).
  • В случае проблем полезна возможность отправить из системы-отправителя объект целиком, со всеми его атрибутами. И, конечно, принять его, проигнорировав при этом предыдущие ошибочные сообщения.
  • Хороший инструмент возможность изменить объект вручную средствами системы возможно, с выходом в нештатный режим для объектов, правки которых запрещены, и с последующим контролем, что объект действительно получился идентичным. Контроль тут важная часть, так как сложные ошибки иногда возникают из-за одинаковых символов с разными кодами, двойных, неразрывных или концевых пробелов и прочих деталей кодировки. При этом стоит учитывать, что интеграция, хранение и интерфейс системы могут работать в разных кодировках.

Поддержка распределенных ограничений целостности


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

А вот если каталог товаров ведет одна система, справочник контрагентов другая, а заказы третья, то задача усложняется. При обработке заказа проверить атрибуты товара проблем не будет. А вот при изменении атрибутов товара или контрагента проверить заказы будет непросто. Потому что систем ведения заказов может быть много, а какие атрибуты являются значимыми неизвестно. Можно, конечно, эмулировать двухфазную транзакцию, когда сначала во все системы посылается сообщение о намерении изменить атрибуты, и только после подтверждения всеми системами готовности к такому изменению сообщать о нем. Но это чрезвычайно сложный протокол. К тому же в полной реализации между подтверждением готовности к изменению и приходом новых значений система-получатель должна работать в особом режиме, обеспечивающим как принятие изменений, так и отказ от него. По сути, в этот период атрибут теряет конкретное значение, у него оказывается два варианта. И хотя я видел реализацию таких двухфазных протоколов, на практике от них больше проблем, чем пользы.

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



Сверка данных


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

Конечно, при больших объемах независимая передача всех объектов для контроля невозможна. Однако для разбора ошибок однократная выгрузка всех объектов из обеих систем с их сверкой может оказаться вполне приемлемым решением. В случае, если их все-таки слишком много можно проводить сверку интегральных показателей по группам объектов. Например, эффективным способом сверки часто является сравнение текстовых файлов если их выгружать отсортированными по ключу или так, чтобы первые позиции обеспечивали текстовую сортировку. Можно пользоваться стандартным diff или его аналогами. А с некоторыми командами мы использовали такой подход не только для сортировки, но и для интеграции с legacy-системой, которая не умела выгружать изменения, в то время как по бизнес-процессам были правки документов в прошлое. Приходилось выгружать полную витрину за полтора года, а потом сортировать, сравнивать и получать ежедневную порцию изменений. И все это тянул слабенький комп под unix с помощью стандартных утилит это было еще до эпохи облаков.

Если же по интеграции передаются вызовы процедур, изменяющие множество объектов, то результат может зависеть от состояния данных, включая обработку других сообщений, поступивших по интеграции (при том, что порядок может быть не гарантирован). Например, в одной из наших систем была передача назначения скидок, действующая на группы магазинов и товаров интерфейс пользователя работал именно в этих категориях. И оказалось, что в системе-получателе на результат действия влияет в том числе текущее состояние классификации товаров и магазинов по группам (которое также поступало из основной системы). Поэтому последовательность обработки сообщений была очень существенной, а при ошибке вообще приходилось останавливать всю серию связанных сообщений. Переходить на низкий уровень передаче не хотелось из-за объемов информации, но работа без контроля иногда приводила к сложным ошибкам, которые было невозможно поймать. Решением стала передача в сообщении количества объектов, на которые должна подействовать скидка сигнал об ошибке начал своевременно приходить, а так как сама ситуация была крайне редкой, ее ручной разбор не вызывал проблем.

Уведомления


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

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

Продолжение следует


На этом я заканчиваю сегодняшнюю статью.

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

На весенний и осенний сезоны 2021 года открыт прием докладов на конференции. Для 2021 года мы подготовили 14 конференций, в том числе и перенесенных с этого года. Смотрите план наших конференций на весь 2021 год с датами закрытия Call for Papers.
Изучайте, подбирайте конференцию для себя!
Подробнее..

Перевод Новое тестирование фичей в Django 3.2

01.03.2021 20:22:05 | Автор: admin

Пару недель назад Django 3.2 выпустил свой первый альфа-релиз, а финальный релиз выйдет в апреле. Он содержит микс новых возможностей, о которых вы можете прочитать в примечаниях к релизу. Эта статья посвящена изменениям в тестировании, некоторые из которых можно получить на более ранних версиях Django с пакетами backport.

1. Изоляция setUpTestData()

В примечании к релизу говорится:

Объекты, назначенные для классификации атрибутов в TestCase.setUpTestData() теперь выделяются для каждого тестового метода.

setUpTestData() очень полезный прием для быстрого выполнения тестов, и это изменение делает его использование намного проще.

Прием TestCase.setUp() нередко используется из юнит-теста для создания экземпляров моделей, которые используются в каждом тесте:

from django.test import TestCasefrom example.core.models import Bookclass ExampleTests(TestCase):    def setUp(self):        self.book = Book.objects.create(title="Meditations")

Тест-раннер вызывает setUp() перед каждым тестом. Это дает простую изоляцию тестов, так как берутся свежие данные для каждого теста. Недостатком такого подхода является то, что setUp() запускается много раз, что при большом объеме данных или тестов может происходить довольно медленно.

setUpTestData() позволяет создавать данные на уровне класса один раз на TestCase. Его использование очень похоже на setUp(), только это метод класса:

from django.test import TestCasefrom example.core.models import Bookclass ExampleTests(TestCase):    @classmethod    def setUpTestData(cls):        cls.book = Book.objects.create(title="Meditations")

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

Возьмем, к примеру, эти тесты:

from django.test import TestCasefrom example.core.models import Bookclass SetUpTestDataTests(TestCase):    @classmethod    def setUpTestData(cls):        cls.book = Book.objects.create(title="Meditations")    def test_that_changes_title(self):        self.book.title = "Antifragile"    def test_that_reads_title_from_db(self):        db_title = Book.objects.get().title        assert db_title == "Meditations"    def test_that_reads_in_memory_title(self):        assert self.book.title == "Meditations"

Если мы запустим их на Django 3.1, то финальный тест провалится:

$ ./manage.py test example.core.tests.test_setuptestdataCreating test database for alias 'default'...System check identified no issues (0 silenced)..F.======================================================================FAIL: test_that_reads_in_memory_title (example.core.tests.test_setuptestdata.SetUpTestDataTests)----------------------------------------------------------------------Traceback (most recent call last):  File "/.../example/core/tests/test_setuptestdata.py", line 19, in test_that_reads_in_memory_title    assert self.book.title == "Meditations"AssertionError----------------------------------------------------------------------Ran 3 tests in 0.002sFAILED (failures=1)Destroying test database for alias 'default'...

Это связано с тем, что in-memory изменение из test_that_changes_title() сохраняется между тестами. Это происходит в Django 3.2 за счет копирования объектов доступа в каждом тесте, поэтому в каждом тесте используется отдельная изолированная копия экземпляра модели in-memory. Теперь тесты проходят:

$ ./manage.py test example.core.tests.test_setuptestdataCreating test database for alias 'default'...System check identified no issues (0 silenced)....----------------------------------------------------------------------Ran 3 tests in 0.002sOKDestroying test database for alias 'default'...

Спасибо Simon Charette за изначальное создание этой функциональности в проекте django-testdata, и до его объединения в систему Django. На старых версиях Django вы можете использовать django тест-данные для той же изоляции, добавив декоратор@wrap_testdata в ваши методы setUpTestData(). Он очень удобен, и я добавлял его в каждый проект, над которым работал.

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

2. Использование faulthandler по умолчанию

В примечании к релизу говорится:

DiscoverRunner сейчас использует faulthandler по умолчанию.

Это небольшое улучшение, которое может помочь вам дебаггить сбои низкого уровня. Модуль Python faulthandler предоставляет способ сброса экстренной трассировки в ответ на проблемы, которые приводят к сбою в работе интерпретатора Python.Тогда тестовый runner Django использует faulthandler. Подобное решение было скопировано из pytest, который делает то же самое.

Проблемы, которые ловит faulthandler, обычно возникают в библиотеках на языке C, например, в драйверах баз данных. Например, OS сигнал SIGSEGV указывает на ошибку сегментации, что означает попытку чтения памяти, не принадлежащей текущему процессу. Мы можем эмулировать это на Python, напрямую посылая сигнал самим себе:

import osimport signalfrom django.test import SimpleTestCaseclass FaulthandlerTests(SimpleTestCase):    def test_segv(self):        # Directly trigger the segmentation fault        # signal, which normally occurs due to        # unsafe memory access in C        os.kill(os.getpid(), signal.SIGSEGV)

Если мы делаем тест в Django 3.1, мы видим это:

$ ./manage.py test example.core.tests.test_faulthandlerSystem check identified no issues (0 silenced).[1]    31127 segmentation fault  ./manage.py test

Это нам не очень помогает, так как нет никакой зацепки на то, что вызвало ошибку сегментации.

Вместо этого мы видим трассировку на Django 3.2:

$ ./manage.py test example.core.tests.test_faulthandlerSystem check identified no issues (0 silenced).Fatal Python error: Segmentation faultCurrent thread 0x000000010ed1bdc0 (most recent call first):  File "/.../example/core/tests/test_faulthandler.py", line 12 in test_segv  File "/.../python3.9/unittest/case.py", line 550 in _callTestMethod  ...  File "/.../django/test/runner.py", line 668 in run_suite  ...  File "/..././manage.py", line 17 in main  File "/..././manage.py", line 21 in <module>[1]    31509 segmentation fault  ./manage.py test

( Сокращенно )

Faulthandler не может генерировать точно такую же трассировку, как стандартное исключение в Python, но он дает нам много информации для дибаггинга сбоя.

3. Timing (тайминг)

В примечании к релизу говорится:

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

Команда manage.py test включает опцию --timing, которая активирует несколько строк вывода в конце пробного тест-запуска для подведения итогов по настройке базы данных и времени:

$ ./manage.py test --timingCreating test database for alias 'default'...System check identified no issues (0 silenced)....----------------------------------------------------------------------Ran 3 tests in 0.002sOKDestroying test database for alias 'default'...Total database setup took 0.019s  Creating 'default' took 0.019sTotal database teardown took 0.000sTotal run took 0.028s

Благодарим Ахмада А. Хуссейна за участие в этом мероприятии в рамках Google Summer of Code 2020.

Если вы используете pytest, опция --durations N работает схоже.

Из-за системы фикстуры pytest время настройки базы данных будет отображаться как время настройки (setup time) только для одного теста, что сделает этот тест более медленным, чем он есть на самом деле.

4. Обратный вызов (callbacks) тестаtransaction.on_commit()

В примечании к релизу говорится:

Новый метод TestCase.captureOnCommitCallbacks() собирает функции обратного вызова (callbacks functions), переданные в transaction.on_commit(). Это позволяет вам тестировать эти callbacks, не используя при этом более медленный TransactionTestCase.

Это вклад, который я ранее сделал и о котором ранее рассказывал.

Итак, представьте, что вы используете опцию ATOMIC_REQUESTSот Django, чтобы перевести каждый вид в транзакцию (а я думаю, что так и должно быть!). Затем вам нужно использовать функцию transaction.on_commit() для выполнения любых действий, которые зависят от того, насколько длительно данные хранятся в базе данных. Например, в этом простом представлении для формы контактов:

from django.db import transactionfrom django.views.decorators.http import require_http_methodsfrom example.core.models import ContactAttempt@require_http_methods(("POST",))def contact(request):    message = request.POST.get('message', '')    attempt = ContactAttempt.objects.create(message=message)    @transaction.on_commit    def send_email():        send_contact_form_email(attempt)    return redirect('/contact/success/')

Мы не посылаем сообщения по электронной почте, если только транзакция не сохраняет изменения, так как в противном случае в базе данных не будет ContactAttempt.

Это правильный способ написания подобного вида, но ранее было сложно протестировать callback (обратный вызов), переданный функции on_commit(). Django не будет запускать callback без сохранения транзакции, а его TestCase избегает сохранения, и вместо этого откатывает (rollback) транзакцию, так что это повторяется при каждом тесте.

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

(Я ранее говорил об увеличении скорости в три раза благодаря конвертации тестов из TransactionTestCase в TestCase.)

Решением в Django 3.2 является новая функция captureOnCommitCallbacks(), которую мы используем в качестве контекстного менеджера. Она захватывает любые callbacks и позволяет вам добавлять утверждения или проверять их эффект. Мы можем использовать это, чтобы проверить наше мнение таким образом:

from django.core import mailfrom django.test import TestCasefrom example.core.models import ContactAttemptclass ContactTests(TestCase):    def test_post(self):        with self.captureOnCommitCallbacks(execute=True) as callbacks:            response = self.client.post(                "/contact/",                {"message": "I like your site"},            )        assert response.status_code == 302        assert response["location"] == "/contact/success/"        assert ContactAttempt.objects.get().message == "I like your site"        assert len(callbacks) == 1        assert len(mail.outbox) == 1        assert mail.outbox[0].subject == "Contact Form"        assert mail.outbox[0].body == "I like your site"

Итак, мы используем captureOnCommitCallbacks() по запросу тестового клиента на просмотр, передавая execute флаг, чтобы указать, что фальшивое сохранение (коммит) должно запускать все callbacks. Затем мы проверяем HTTP-ответ и состояние базы данных, прежде чем проверить электронную почту, отправленную обратным вызовом (callback). Наш тест затем покрывает все на просмотре, оставаясь быстрым и классным!

Чтобы использовать captureOnCommitCallbacks() в ранних версиях Django, установите django-capture-on-commit-callbacks.

5. Улучшенный assertQuerysetEqual()

В примечании к релизу говорится:

TransactionTestCase.assertQuerysetEqual() в данный момент поддерживает прямое сравнение с другой выборкой элементов запроса в Django

Если вы используете assertQuerysetEqual() в ваших тестах, это изменение точно улучшит вашу жизнь!

В дополнение к Django 3.2, assertQuerysetEqual() требует от вас сравнения с QuerySet после трансформации. Далее происходит переход по умолчанию к repr(). Таким образом, тесты, использующие его, обычно проходят список предварительно вычисленных repr() strings для вышеупомянутого сравнения:

from django.test import TestCasefrom example.core.models import Bookclass AssertQuerySetEqualTests(TestCase):    def test_comparison(self):        Book.objects.create(title="Meditations")        Book.objects.create(title="Antifragile")        self.assertQuerysetEqual(            Book.objects.order_by("title"),            ["<Book: Antifragile>", "<Book: Meditations>"],        )

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

Из Django 3.2 можно передать QuerySet или список объектов для сравнения, что позволяет упростить тест:

from django.test import TestCasefrom example.core.models import Bookclass AssertQuerySetEqualTests(TestCase):    def test_comparison(self):        book1 = Book.objects.create(title="Meditations")        book2 = Book.objects.create(title="Antifragile")        self.assertQuerysetEqual(            Book.objects.order_by("title"),            [book2, book1],        )

Спасибо Питеру Инглсби и Хасану Рамезани за то, что они внесли эти изменения. Они помогли улучшить тестовый набор Django.

Финал

Наслаждайтесь этими изменениями, когда Django 3.2 выйдет или сделайте это раньше через пакет backport.


Перевод статьи подготовлен в преддверии старта курса Web-разработчик на Python.

Также приглашаем всех желающих посмотреть открытый вебинар на тему Использование сторонних библиотек в django. На занятии мы рассмотрим общие принципы установки и использования сторонних библиотек вместе с django; а также научимся пользоваться несколькими популярными библиотеками: django-debug-toolbar, django-cms, django-cleanup и т.д.

Подробнее..

Перевод Почему японский веб-дизайн настолько другой?

06.12.2020 16:18:24 | Автор: admin
Коничива Хабр!
В глазах многих людей Япония земля спокойствия дзен-садов, безмятежные храмы и изысканные чайные церемонии. Как традиционные, так и современные японские архитектура, книги и журналы предмет зависти дизайнеров всего мира. Однако по каким-то причинам практически ни одно из этих умений не перенесено на цифровые продукты, в частности на веб-сайты, большинство из которых выглядят так, как будто они появились примерно в 1998 году. Теории о том, почему всё именно так, многочисленны, и сегодня, в преддверии старта курса Профессия Веб-разработчик попытаемся развить некоторые из наиболее распространенных теорий в этом посте.





Пройдитесь по самым популярным сайтам Японии и вот что вы можете увидеть (смотрите Goo, Rakuten, Yomiuri, NicoNico, OKWave, @cosme, и другие):

  • Плотный, тесно упакованный текст.
  • Крошечные изображения низкого качества.
  • Больше колонок, чем вы можете сосчитать.
  • Яркие мигающие цвета и баннеры.
  • Переизбыток устаревших технологий, таких как Flash.

Почему же всё именно так?

Языковые различия




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

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

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

Культурные различия




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

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

Реклама вместо того чтобы рассматривать Интернет как инструмент включения людей, японские компании часто смотрят на Интернет как на просто ещё одну рекламную платформу, чтобы сообщить о товаре как можно громче. Веб-сайты в конечном счёте представляют собой максимальную концентрацию информации в наименьшем пространстве, сродни брошюре, а не интерактивный инструмент.

Городской ландшафт прогуляйтесь по одному из центров Токио, например Сибуя: вас непрерывно бомбардируют яркой неоновой рекламой, шумными салонами пачинко (салоны аркадных игр), толпами буйных наёмников или школьников. Та же хаотичная деловитость улиц, кажется, перешла в веб. Кроме того, поскольку физическое пространство в Японии стоит дорого, оно не тратится впустую, и то же самое касается пустого пространства на веб-странице.

Вакансии в области веба посмотрите на любой сайт вакансий в Японии, и вы всё равно увидите рекламу таких ролей, как веб-мастер и веб-администратор, восходящие к тому времени, когда компания нанимала одного ИТ-специалиста написать код руками и запустить весь веб-сайт многие до сих пор так делают. С другой стороны, творческие люди хотят творческой свободы, которую они вряд ли найдут в крупной японской корпорации, поэтому они идут в другое место.

Технические различия




Мобильное наследие Япония пользовалась своим собственным мобильным Интернетом на продвинутых телефонах-раскладушках задолго до появления iPhone и в ещё большем количестве, чем на ПК. Тогда экраны были крошечными, и сайты должны были быть спроектированы так, чтобы втиснуть контент в это маленькое пространство, и это продолжает оказывать влияние на то, что происходит сейчас.

Шрифты для веба имеет место нехватка веб-шрифтов для нелатинских языков (китайский, японский и т. д.). Это связано с тем, что каждый шрифт требует индивидуального дизайна в тысячи символов, что непомерно дорого, трудоёмко и такой шрифт требует больше времени на загрузку. По этим причинам дизайнеры предпочитают для отображения нестандартных шрифтов графику, а не обычный текст.

Windows XP & IE 6 хотя число людей, использующих древнее программное обеспечение Microsoft, быстро уменьшается, всё ещё существует достаточное количество пользователей с этими динозаврами, особенно в корпоративной среде. Хватит уже!



Гуляя по Токио, я часто испытываю чувство, будто застрял в будущем, каким его видели в восьмидесятых, и во многом именно эти противоположности характеризует дизайн ландшафта в Японии. С одной стороны, у нас есть огромные конгломераты, производящие скучную массовую продукцию, а с другой мы видим мастеров-ремесленников, создающих вещи невероятной красоты и функциональности.

Более позитивный момент небольшие дизайнерские фирмы и компании, такие как UNIQLO, MUJI, CookPad и Kinokuniya доказывают, что в Японии могут создавать эстетически привлекательные и функциональные веб-сайты. Будем надеяться, что остальные научатся у них и скоро наверстают упущенное, с помощью толковых специалистов с нужными знаниями. Как раз таких мы готовим на наших курсах приходите, научим и вас. А промокод HABR, добавит 10 % к скидке на баннере.

image



Рекомендуемые статьи


Подробнее..

Обходим проверку сертификата SSL

13.12.2020 00:13:26 | Автор: admin

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





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


Всем известно, что при посещении сайта у которого временно что-то случилось c сертификатом вы обнаружите предупреждение, которое показывается, если сертификат безопасности не является доверенным net::ERR_CERT_AUTHORITY_INVALID?


Привет онлайн-кинотеатрам

Все современные браузеры показывают сообщение об ошибке HSTS


Что такое HSTS
HSTS (HTTP Strict Transport Security) это механизм защиты от даунгрейд-атак на TLS, указывающий браузеру всегда использовать TLS для сайтов с соответствующими политиками.

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



Но не во всех браузерах как оказывается, есть данная возможность. Так я столкнулся с данной проблемой в Chrome на Mac OS


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


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


Все хромоподобные браузеры (Chrome, Opera, Edge ) могут открыть небезопасную веб страницу, если на английской раскладке клавиатуры набрать фразу:


thisisunsafe


прямо на данной веб странице. Это даст возможность работать с сайтом без оповещение об ошибке на момент текущей сессии браузера, пока вы не закроете вкладку Chrome.


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


Для Windows


C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --ignore-certificate-errors




Для Mac OS


/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --ignore-certificate-errors --ignore-urlfetcher-cert-requests &> /dev/null


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


Если вы оставите сертификат ненадежным, то некоторые вещи не будут работать. Например, кэширование полностью игнорируется для ненадежных сертификатов.


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



*Так же есть метод с добавлением сертификатов тестируемого сайта в конфиги браузера Настройки->Безопасность->Настроить сертификаты->Импорт но мне он показался не продуктивным и очень муторным, поэтому не привожу


Надеюсь моя краткая статья кому-то пригодится при разработке и тестировании сайтов =)

Подробнее..

Вам показалось! Все о Perceived Performance

21.01.2021 14:15:10 | Автор: admin

Перед вами быстрый, удобный и отзывчивый сайт? Возможно, это не результат плодотворной работы множества людей, а всего лишь набор психологических и инженерных трюков, направленных на улучшение Perceived Performance.

В большинстве случаев с ростом реальной производительности улучшается и Perceived Performance. А когда реальная производительность не может быть с легкостью увеличена, существует возможность поднять видимую. В своем докладе на Frontend Live 2020 бывший разработчик Avito Frontend Architecture Алексей Охрименко рассказал о приемах, которые улучшают ощущение скорости там, где ускорить уже нельзя.

Производительность обязательное условие успеха современных Web-приложений. Есть множество исследований от Amazon и Google, которые говорят, что понижение производительности прямо пропорционально потере денег и ведет к слабой удовлетворенности вашими сервисами (что снова заставляет терять деньги).

Первопричина полученного стресса ожидание. Научно доказано, что оно может вызывать:

  • беспокойство;

  • неуверенность;

  • дискомфорт;

  • раздражение;

  • скуку.

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

Самое простое решение все делать быстро. Но прежде, чем вы скажете: Спасибо, капитан!, хочу напомнить, что увеличение производительности ведет к прямому уменьшению времени ожидания.

Не игнорируйте этот момент: вы обязательно должны его учитывать.

Для этого есть множество разнообразных техник, в том числе:

  • lighthouse;

  • devTools profiler.

Но даже если все сделать идеально, этого может оказаться недостаточно.

Есть интересная история про аэропорт Huston. Она отлично вписывается и в современные реалии разработчиков.

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

Люди часто жаловались на долгое ожидание багажа в аэропорту. И инженеры аэропорта Huston не спали ночами, работали сверхурочно, но реализовали выдачу багажа всего за 8 минут. Однако клиенты все равно продолжали жаловаться.

Инженеры не знали, что делать. И они решили попробовать один трюк. Высадив людей как можно дальше от зоны выдачи багажа, они вынудили их быть в активном ожидании. Пока те добирались до места назначения, багаж уже ждал их. В результате все жалобы прекратились. Но самое интересное, что реальное время выдачи багажа осталось абсолютно таким же: 8 минут.

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

Perceived Performance

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

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

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

Все это базируется на том, что люди не очень хорошо умеют измерять реальную производительность. И именно эту особенность можно эксплуатировать.

Все дальнейшие примеры будут для Angular приложений, но, несмотря на это, они применимы к любому современному фреймворку. Приступим!

Не блокируйте пользователя

Первый совет: ни в коем случае не стоит блокировать пользователя. Вы можете сейчас сказать: Я и не блокирую!.

Попробуйте узнать себя в этом примере:

Допустим, мы кликаем на удаление какого-то элемента, запрашиваем данные, после чего удаляем.

Все равно не узнаете? А так?

Спиннеры это не выход! Хоть они и могут стать ленивым способом разобраться с неудобной ситуацией.

Что можно предложить в качестве альтернативы спиннеру?

Можно нажать на кнопку УДАЛИТЬ и показать статус этой кнопки (item удаляется только для одного элемента), не демонстрируя спиннер. В дальнейшем можно отправить запрос на сервер, и когда он придет, показать, что элемент удалился, либо при ошибке передать данные о ней. Вы можете возразить: Но я могу делать только 1 запрос за раз! это ограничение бэкенда. С помощью RxJs и оператора concat можно буквально одной строчкой кода создать минимальную очередь:

Более серьезная имплементация, конечно, займет больше, чем одну строчку.

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

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

В Angular есть ngx-spinner, который поддерживает такой функционал.

Это, как минимум, уменьшит время ожидания, и пользователь сможет в этот момент сделать хоть что-то.

Обманывайте

Обман зачастую базируется на иллюзиях скорости.

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

Иллюзия базируется на простом эффекте: чем больше точек, тем больше Motion Blur (размытие движения). Этот трюк используется в мультфильмах. Возможно, вы видели, что когда койот бежит очень быстро, у него размываются ноги, и вместо них появляется облако.

Где можно применить такую методологию?

  • Progress Bar;

Есть исследование, показывающее, что если добавить полоски, которые идут в обратном направлении внутри Progress Bar, то визуально он выглядит как более быстрый. В такой настройке можно получить до 12% ускорения, просто применив дополнительный скин. И пользователи воспримут работу, прошедшую под этим Progress Bar, на 12% быстрее. Вот пример того, как можно реализовать такой слайдер на CSS.

  • Скелетон;

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

Скелетон это некое схематическое отображение сайта до момента его загрузки:

В этом примере мы видим, где будут расположены чаты.

Существует исследование, которое показывает, что люди воспринимают скелетоны быстрее от 10 до 20%.

То есть по ощущениям пользователей, сайты со скелетоном работают быстрее.

Существует огромное количество нужных компонентов для Angular, React, View. К примеру, для Angular есть skeleton-loader, в котором можно прописать внешний вид и сконфигурировать его. После чего мы получим наш скелетон:

  • Экспоненциальная выдержка.

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

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

Это одна из best practice в энтерпрайз-приложениях, потому что бэкенд может не работать по разным причинам. Например, происходит деплой или хитрая маршрутизация. В любом случае очень хорошее решение: попробовать повторить. Ведь никакое API не дает 100% гарантии, 99,9% uptime.

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

Но даже с этим сценарием мы сами себе можем сделать DDOS (Distributed Denial of Service). На это попадались многие компании. Например, Apple с запуском своего сервиса MobileMe.

В чем идея? Представьте на секунду, что ваш сервис падает под нагрузкой, то есть он с ней не справляется. Если сервер перегружен, то скорее всего ответит статус-кодом 500. Если вы попробуете еще раз, возможно, следующий запрос получит ответ.

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

Best practice: применять exponential backoff. В rxjs есть хороший дополнительный npm пакет backoff-rxjs, который за вас имплементирует данный паттерн.

Имплементация очень простая, 10 строчек кода. Здесь вы можете обойтись одной. Указываете интервал, через который начнутся повторы, количество попыток, и сбрасывать ли увеличивающийся таймер. То есть вы увеличиваете по экспоненте каждую следующую попытку: первую делаете через 1 с, следующую через 2 с, потом через 4 с и т.д.

Играя с этими настройками, вы можете настраивать их под ваше API.

Следующий совет очень простой добавить Math.random() для initialInterval:

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

Предугадывайте!

Как уменьшить ожидание, когда невозможно ускорить процесс?

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

  • Предзагрузка картинок;

Один из самых простых примеров это предзагрузка картинок. К примеру, у вас есть SPA-приложение. Вы открываете одну страничку, а на следующей есть набор иконок. Вы можете очень простым скриптом написать preload и загружать на конкретной странице картинки, необходимые для другой:

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

  • Предзагрузка 18+

Наверняка вы сталкивались в HTML со стеком link, который позволяет переподключить stylesheets:

Немного поменяв атрибуты, мы можем применить его для предзагрузки:

Можно указать атрибут rel ="preload", сослаться в ссылке на наш элемент (href="styles/main.css"), и в атрибуте as описать тип предзагружаемого контента.

  • prefetch.

Еще один вариант это prefetch:

Главное запомнить, что preload и prefetch два самых полезных инструмента. Отличие preload от prefetch в том, что preload заставляет браузер делать запрос, принуждает его. Обычно это имеет смысл, если вы предзагружаете ресурс на текущей странице, к примеру, hero images (большую картинку).

ОК, это уже лучше, но есть одна маленькая проблема.

Если взять какой-нибудь среднестатистический сайт и начать префетчить все JavaScript модули, то средний рост по больнице составляет 3 МБ. Если мы будем префетчить только то, что видим на странице, получаем примерно половину 1,2 МБ. Ситуация получше, но все равно не очень.

Что же делать?

Давайте добавим Machine Learning

Сделать это можно с помощью библиотеки Guess.js. Она создана разработчиками Google и интегрирована с Google Analytics.

Анализируя паттерны поведения пользователей и, подключаясь к вашему приложению и системе сборки, она может интеллектуально делать prefetch только 7% на странице.

При этом эта библиотека будет точна на 90%. Загрузив всего 7%, она угадает желания 90% пользователей. В результате вы выигрываете и от prefetching/preloading, и от того, что не загружаете все подряд. Guess.js это идеальный баланс.

Сейчас Guess.js работает из коробки с Angular, Nuxt js, Next.js и Gatsby. Подключение очень легкое.

Поговорим о Click-ах

Что можно сделать, чтобы уменьшить ожидание?

Как предугадать, на что кликнет пользователь? Есть очевидный ответ.

У нас есть событие, которое называется mousedown. Оно срабатывает в среднем на 100-200 мс раньше, чем событие Click.

Применяется очень просто:

Просто поменяв click на mousedown, мы можем выиграть 100-200 мс.

Мы можем заранее предсказать, что пользователь кликнет на ссылку.

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

Опять магия ML? Нет. Существует паттерн: когда мы хотим на что-то кликнуть, мы замедляем движение (чтобы было легче попасть мышкой на нужный элемент) .

Есть библиотека, которая анализирует скорость, и благодаря этому может предсказать, куда я кликну.

Библиотека называется futurelink. Ее можно использовать абсолютно с любым фреймворком:

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

Что пользователь хочет получить при переходе на страницу? В большинстве сценариев: HTML, CSS и немного картинок.

Все это можно реализовать за счет серверного рендеринга SSR.

В Angular для этого достаточно добавить одну команду:

ng add @nguniversal/express-engine

В большинстве случаев это работает замечательно, и у вас появится Server-Side Rendering.

Но что, если вы не на Angular? Или у вас большой проект, и вы понимаете, что внедрение серверного рендеринга потребует довольно большого количества усилий?

Здесь можно воспользоваться статическим prerender: отрендерить страницы заранее, превратить их в HTML. Для этого есть классный плагин для webpack, который называется PrerenderSPAPlugin:

В нем нужно указываете директорию, куда вы хотите сохранять пререндеренные urls, и перечислить те, для которых нужно отрендерить контент заранее.

Но вы можете сделать все еще проще: зайти в свое SPA приложение и написать:

document.documentElement.outerHTML,

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

Заключение

Несмотря на то что Perceived Performance очень субъективная метрика, ее можно и нужно измерять. Об этом говорилось в докладе Виктора Русаковича на FrontendConf 2019.

Он рассказывал о том, что в Скелетоне есть анимация в плавном фоне, и слева направо она воспринимается на 68% быстрее, чем справа налево. Есть разные исследования, которые показывают, что неправильно примененные техники Perceived Performance могут визуально сделать сайт хуже. Поэтому обязательно тестируйте.

Сделать это можно при помощи сервиса под названием Яндекс.Толока.

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

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

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

Конференция, посвященная всем аспектам разработки клиентской части веб проектов, FrontendConf 2021 пройдет 29 и 30 апреля. Билеты можно приобрести здесь. Вы можете успеть купить их до повышения цены!

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

Черновик

Подробнее..

Перевод Минимальный размер контента в CSS grid

03.02.2021 14:08:11 | Автор: admin
Иногда, когда вы пишете компонент, то вдруг замечаете странную полосу горизонтальной прокрутки. Снова и снова вы пытаетесь исправить положение, только чтобы позже понять, что причина в чём-то другом. Сколько раз так было? В этой статье я растолкую хитрую проблему, которая может стоить часов проб и ошибок; связана эта проблема с макетом сетки CSS, и я подумал, что о ней стоит написать. Прежде чем начать, я хочу дать некоторый контекст. Вот несколько вещей, которые следует принять во внимание. Представьте, что вы:

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

Учитывая всё это, давайте погрузимся в проблему.




Что должно получиться


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


Определим проблему


Работая над разделом контейнера с прокруткой, я заметил горизонтальную прокрутку по всей странице, увидеть которую не ожидал.


У раздела было свойство display: flex без обёртки, поэтому контент мог оставаться в той же строке. Кроме того, чтобы разрешить прокрутку по оси x, я воспользовался overflow-x: auto.

    .section {        display: flex;        overflow-x: auto;      }

Однако эффекта не последовало. Это сбивало с толку: я был уверен, что так я делаю контейнер с прокруткой. Я открыл браузер DevTools, чтобы проверить раздел main, и заметил, что раздел очень широкий. Расширился он за счёт прокручиваемого контейнера.


Странно, правда? Когда я впервые увидел эту проблему, то задался следующими вопросами:

  • Может, я забыл добавить overflow-x: hidden?
  • Что-то не так с flexbox?

Я дважды перепроверил flexbox и overflow-x. Всё должно было работать так, как я ожидал. Тогда я заподозрил, что причиной проблемы может оказаться CSS-сетка (grid) для родительского элемента. Проверил подозрение, и оно подтвердилось. Макет сломался из-за grid.

Первопричиной проблемы могла быть особенность CSS (т. е. из-за какого-то контекста ожидается именно такое поведение) либо то, что свойство неверно реализовали в браузере.

Почему же появилась прокрутка?


Возможно, вы задумались, почему grid прикрепляет прокрутку к контейнеру? Смотрите: вот сетка, на которой расположены разделы main и aside.

    <div class="wrapper">        <main>          <section class="section"></section>        </main>        <aside></aside>      </div>

@media (min-width: 1020px) {    .wrapper {      display: grid;      grid-template-columns: 1fr 248px;      grid-gap: 40px;    }  }

В свойствах main есть значение 1fr. Это означает, что main займет доступное пространство, кроме aside и отступа. Это не подлежит сомнению. Однако минимальный размер содержимого элемента сетки auto. Это означает, что элемент сетки может расширяться из-за длинного содержимого (в нашем случае из-за контейнера с прокруткой).

Как убрать лишнюю прокрутку?


Решается проблема так: нужно сообщить браузеру, что нам необходим конкретный и фиксированный минимальный размер, но не auto. Сделать это можно при помощи функции minmax().

.wrapper {    display: grid;    grid-template-columns: minmax(0, 1fr) 248px;    grid-gap: 40px;  }

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

  1. Установить свойство min-width: 0.
  2. Или overflow: hidden.

В зависимости от контекста можно воспользоваться одним из двух решений выше. Однако эти решения могут иметь кое-какие побочные эффекты, один из них связан с overflow-hidden. Представьте, что дочерний элемент раздела main имеет декоративный псевдоэлемент, который размещается вне границ main. В таком случае, если применить overflow-hidden, свойство обрежет этот псевдоэлемент.


На рисунке выше у нас два элемента, которые расположены вне main (кнопка шаринга слева и декоративная фигурка внизу справа). Учитывая это, вы должны выбрать решение, которое лучше всего подходит именно в вашем случае.

Статьи по теме





image



Подробнее..

MastermindCMS что это такое? Система управления контентом? Фреймворк?

28.05.2021 04:14:05 | Автор: admin

Вступление

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

Миллионы web-проектов увидели свет, но изо дня в день программисты все еще пишут тонны исходного кода, решая похожие задачи на разных инструментах. Речь в этой статье пойдет о технологии, которую мы разрабатываем на протяжении 4-х лет. Я уже ранее рассказывал о том, какой была моя задумка и цель в создании данного продукта и чего именно я хотел добиться, программируя инструмент для повседневной рутинной разработки веб-приложений. Мне пришлось пройти свой путь от презентаций моего продукта на стартап-pitch'ах и хакатонах и до получения первого реального проекта в сети, где я смог успешно применить мою разработку.

Все началось в далеком 2017 году, когда мне пришла идея написать для себя сайт. Я, недолго думая, взял Drupal и настроил его как headless-cms. Мне хотелось написать отдельно фронтэнд и не копаться с темами от Drupal. Но что-то пошло не так! Я столкнулся с множеством ограничений в проектировании сущностей в административном интерфейсе. Тогда я решил попробовать это сделать на WordPress. Но я совсем не ожидал, что мне придется создавать отдельные контроллеры под каждый тип сущности. Но честно признаться - меня это расстроило. В Drupal хотя бы есть Views, которые относительно легко сконфигурировать в административной консоли и создать endpoint'ы для доступа через REST API, но тем не менее там есть свои ограничения. После этого я провел небольшой анализ существующих CMS и понял, что придется писать все под себя.

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

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

На данный момент в MastermindCMS2 насчитывается 12-функциональных модулей, два из которых не активны и потеряли свою актуальность. Плюс ко всему этому существует отдельный проект Mastermind Microservices, включающий в себя интеграции сторонних проектов.

Что же в итоге может MastermindCMS2? Ниже я дам краткое описание функций каждого модуля по-отдельности и расскажу о том, как работает движок-шаблонов.

Модули

В основе MastermindCMS2 лежит обычный Spring Rest Controller. В дополнении для асинхронного взаимодействия между клиентом и сервером был использован Spring WebSocket Controller.

Application модуль обработки HTTP-запросов.

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

Common тут сложены все общие классы и инструменты, использованные в проекте.

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

Utilities почти тоже самое что и Common, но еще имеет классы, использованные в проекте Mastermind Microservices.

Blogging модуль содержит структуры и сервисы для блогов.

Commerce модуль покрывает функционал для электронной коммерции. Более того, структура объектов в базе данных спроектирована так, что без проблем можно расширять сущности прямо из административной панели.

EmailSender тут название говорит само за себя, так как по сути это модуль, реализующий функционал отправки писем по электронной почте.

Messaging здесь находиться функционал для построения мессенджеров и чатов.

FileStorage здесь реализовано базовое взаимодействие с файлами или другими словами это файловый менеджер.

i18Next модуль для мультиязычности.

VCS версионирование шаблонов, интеграция с Git. На данный момент дальнейшая разработка не ведется.

Основная концепция

Любой сервис, который написан на Spring и существует в веб-контексте сервера, можно будет вызывать через клиентскую часть фреймворка, а ответ получать в виде JSON или выполнять обновление HTML. Cуществует два способа использования фреймворка.

Первый способ, или основной способ это когда data binding реализуется через SSR (Server-Side Rendering) и клиентская часть фреймворка используется для обновления HTML.

Второй способ, или дополнительный это когда data binding реализуется через сторонние фреймворки, такие как Angular, React, vue.js и т. п., а фреймворк MastemindCMS2 предоставляет универсальный канал получения данных в виде JSON, используя WebSocket в качестве протокола.

Поэтому, проектируя свое приложение, вы не ограничены в выборе фреймворка. MastermindCMS2 дает дополнительную свободу в реализации задач. Вам не нужно работать с данными на клиенте - это уже сделано за вас! Остается только связать дизайн с функционалом.

В отличии от Spring Data REST, в MastermindCMS2 реализованы готовые методы для управления данными.

Теги

В MastermindCMS2 существует 8 типов тегов. Этого вполне достаточно для создания динамических шаблонов. Многие сравнивают его с известным Spring Thymeleaf. Безусловно, схожесть есть, но также есть и важное отличие, из-за которого я не стал использовать этот фреймворк в качестве языка шаблонов. На одном из этапов разработки я даже рассматривал интеграцию Spring Thymeleaf в общую систему MastermindCMS2. Так в чем же все-таки различие? А различие состоит в том, что для Spring Thymeleaf нужно писать контроллер для каждой view отдельно, которая в свою очередь повлечет за собой связку части фронтэнда с бекэндом. И тогда MastermindCMS2 теряет универсальность и абстрактность.

На сайте mastermindcms.co в разделе документации вы можете ознакомиться с каждый тегом, а также узнать, как работает клиентская часть фреймворка.

Роутинг

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

Сегментация разработки

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

У нас на проекте были фронтэнд разрабы со знанием только веб стека HTML/CSS/JS и они успешно справлялись с задачами.

А с появлением Mastermind Microservices появилось еще больше гибкости и независимости команд.

Заключение

В заключении я бы хотел написать несколько слов про результат работы над проектом MastermindCMS2.

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

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

Хорошего и продуктивного вам дня!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru