Popover API
Popover API недавно стал поддерживаться всеми современными браузерами, а также попал в топ списка для чтения по результатам State of HTML 2023. Это значит, что пришло время поближе познакомиться с этим API.
Popover API — это механизм для создания различных всплывающих элементов интерфейса (поповеров). Механизм преимущественно декларативный, JavaScript не требуется. При этом механизм добавляет много полезного: открытие/закрытие по кнопке, закрытие по
Поповеры бывают двух видов (на данный момент): автоматические и ручные. Автоматический поповер создаётся при помощи кнопки с атрибутом
При нажатии на кнопку, отображается связанный поповер. При повторном нажатии на кнопку, нажатии клавиши
Ручной поповер создаётся при помощи атрибута
Помимо значения
Сам поповер вырывается из основного потока и помещается в специальный слой
Кнопка управления поповером получает встроенные атрибуты
В Javanoscript у кнопки управления поповером доступны методы
API доступно в Chrome и Edge 114+, Firefox 125+ и Safari 17+. Для более ранних версий можно использовать полифил. Это позволит избавиться от JavaScript-библиотек, которые воспроизводят функциональность Popover API. Когда поддержка будет лучше, полифил можно будет отключить.
API продолжает развиваться. В будущем нас ожидают доработки:
Забавный факт: известно, что все эти новые атрибуты из Popover API объявят устаревшими. Дело в том, что новый Invoker Commands API принесёт с собой новые атрибуты, которые заменят текущую реализацию Popover API. Но об этом в другой раз.
Popover API недавно стал поддерживаться всеми современными браузерами, а также попал в топ списка для чтения по результатам State of HTML 2023. Это значит, что пришло время поближе познакомиться с этим API.
Popover API — это механизм для создания различных всплывающих элементов интерфейса (поповеров). Механизм преимущественно декларативный, JavaScript не требуется. При этом механизм добавляет много полезного: открытие/закрытие по кнопке, закрытие по
Esc и клику вне поповера, встроенные aria-атрибуты, возврат фокуса. Поповеры бывают двух видов (на данный момент): автоматические и ручные. Автоматический поповер создаётся при помощи кнопки с атрибутом
popovertarget, который содержит id поповера. У самого всплывающего элемента при этом должны быть указаны атрибуты popover или popover="auto" и id.<button
type="button"
popovertarget="more"
>
More info
</button>
<div id="more" popover>
<p>More information...</p>
</div>
При нажатии на кнопку, отображается связанный поповер. При повторном нажатии на кнопку, нажатии клавиши
Esc или нажатии в любом месте вне поповера, он скрывается. Ручной поповер создаётся при помощи атрибута
popover="manual". Такой поповер не будет закрыт при нажатии в произвольном месте. Для закрытия требуется кнопка с атрибутом popovertargetaction="hide". Также закрыть ручной поповер можно при помощи Esc.<button
type="button"
popovertarget="more"
>
More info
</button>
<div id="more" popover="manual">
<p>More information...</p>
<button
type="button"
popovertarget="more"
popovertargetaction="hide"
>
Close
</button>
</div>
Помимо значения
hide (только закрыть) доступны значения show (только показать) и toggle (переключить видимость).Сам поповер вырывается из основного потока и помещается в специальный слой
top-layer, который всегда будет выше любого z-index. У поповера есть псевдо-элемент ::backdrop, что позволяет стилизовать задний фон (оверлей). Открытый поповер можно стилизовать через псевдо-класс :popover-open. По умолчанию поповер располагается по центру экрана, а его размеры определяются по контенту. Подробнее про стандартные стили поповера можно прочитать в блоге Mayank. Кнопка управления поповером получает встроенные атрибуты
aria-expanded, и aria-details. Если у поповера роль generic, то она заменяется на group, иначе используется встроенная роль или указанная в атрибуте role. Поповер становится следующим элементом в последовательности табуляции, даже если между ним и кнопкой есть другие интерактивные элементы. При закрытии поповера через Esc, фокус возвращается на кнопку, с помощью которой он был показан. Подробнее про доступность поповера в блоге Hidde. В Javanoscript у кнопки управления поповером доступны методы
showPopover(), hidePopover() и togglePopover() для программного отображения, скрытия и переключения поповера.API доступно в Chrome и Edge 114+, Firefox 125+ и Safari 17+. Для более ранних версий можно использовать полифил. Это позволит избавиться от JavaScript-библиотек, которые воспроизводят функциональность Popover API. Когда поддержка будет лучше, полифил можно будет отключить.
API продолжает развиваться. В будущем нас ожидают доработки:
popover="hint", ::tooltip и role="tooltip" для тултипов, Anchor Positioning API для позиционирования и т.д. Забавный факт: известно, что все эти новые атрибуты из Popover API объявят устаревшими. Дело в том, что новый Invoker Commands API принесёт с собой новые атрибуты, которые заменят текущую реализацию Popover API. Но об этом в другой раз.
GitHub
GitHub - oddbird/popover-polyfill: Polyfills the HTML popover attribute and showPopover/hidePopover/togglePopover methods onto…
Polyfills the HTML popover attribute and showPopover/hidePopover/togglePopover methods onto HTMLElement, as well as the popovertarget and popovertargetaction attributes on <button> el...
❤10🤗1
Как не мучать пользователя плохими контролами
Буду иногда делиться записями докладов, которые я смотрю и которые кажутся мне интересными, важными и близкими.
Буквально вчера опубликовали запись доклада Ильи Бирмана про плохие контролы. Илья на примере разных сайтов показывает, с какими проблемами сталкиваются пользователи, когда дизайнеры и разработчики плохо продумали UX.
Основные выводы из доклада:
- упрощайте прицеливание. Делайте размеры кликабельных областей достаточно большими
- всегда давайте обратную связь. Добавьте эффекты на ховер и клик, покажите лоадер или прогрессбар, отобразите ошибку, измените состояние интерфейса
- не мешайте нажимать. Не блокируйте кнопки, чекбоксы и другие поля ввода, дайте нажать и покажите обратную связь
- не усложняйте поля ввода телефона и даты. Дайте пользователю ввести номер телефона или дату рождения с клавиатуры. Об этом я даже писал в отдельном посте
- карусели — антипаттерн. Избегайте их по возможности в пользу вертикальной прокрутки
Рекомендую посмотреть доклад.
Буду иногда делиться записями докладов, которые я смотрю и которые кажутся мне интересными, важными и близкими.
Буквально вчера опубликовали запись доклада Ильи Бирмана про плохие контролы. Илья на примере разных сайтов показывает, с какими проблемами сталкиваются пользователи, когда дизайнеры и разработчики плохо продумали UX.
Основные выводы из доклада:
- упрощайте прицеливание. Делайте размеры кликабельных областей достаточно большими
- всегда давайте обратную связь. Добавьте эффекты на ховер и клик, покажите лоадер или прогрессбар, отобразите ошибку, измените состояние интерфейса
- не мешайте нажимать. Не блокируйте кнопки, чекбоксы и другие поля ввода, дайте нажать и покажите обратную связь
- не усложняйте поля ввода телефона и даты. Дайте пользователю ввести номер телефона или дату рождения с клавиатуры. Об этом я даже писал в отдельном посте
- карусели — антипаттерн. Избегайте их по возможности в пользу вертикальной прокрутки
Рекомендую посмотреть доклад.
YouTube
Как не замучить пользователя плохими контролами / Илья Бирман
Это Илья Бирман из Дизайн-бюро Артёма Горбунова и его доклад на «Я💛Фронтенд 2024» — нашей главной фронтенд-конференции. На ней мы обсудили, как делать удобные интерфейсы, использовать популярные и не очень инструменты, правильно относиться к себе и сообществу…
👍6🔥6
Результаты State of JS
Опубликованы результаты опроса State of JS 2023. Опрос посвящён JavaScript и его экосистеме: фреймворкам, библиотекам тестирования, сборщикам, утилитам и т.д. С результатами можно ознакомиться по ссылке.
Опубликованы результаты опроса State of JS 2023. Опрос посвящён JavaScript и его экосистеме: фреймворкам, библиотекам тестирования, сборщикам, утилитам и т.д. С результатами можно ознакомиться по ссылке.
Stateofjs
State of JavaScript 2023
The 2023 edition of the annual survey about the latest trends in the JavaScript ecosystem.
👍2🌚1
Случайная задачка: группа только с кнопками
Совершенно случайно мне в голову пришла одна задачка. Звучит она так:
Да, иногда приходят такие мысли 😅.
Где это может пригодиться? Ну, предположим, разрабатывается компонент табов, где должен быть элемент с ролью
Вернёмся к изначальной задаче с кнопками.
Ответ: так сделать можно. И вот как:
И разметка:
Абсолютно нечитаемое месиво из селекторов, но оно работает. Вся магия кроется в сочетании
1) выбери элемент с атрибутом
2) внутри которого вторым дочерним элементом является кнопка
3) и внутри которого нет дочерних элементов, которые не являются кнопкой
Иными словами: выбери группу, в которой есть как минимум две кнопки и нет ничего кроме кнопок.
Перекладывая эту идею на табы, можно получить такой селектор:
Совершенно случайно мне в голову пришла одна задачка. Звучит она так:
Можно ли в CSS выбрать элемент, внутри которого находятся только кнопки, и этих кнопок две и более?
Да, иногда приходят такие мысли 😅.
Где это может пригодиться? Ну, предположим, разрабатывается компонент табов, где должен быть элемент с ролью
tablist, внутри которого могут быть только элементы с ролью tab и как минимум два таких.Вернёмся к изначальной задаче с кнопками.
Ответ: так сделать можно. И вот как:
[role="group"]:has(> button:nth-child(2)):not(:has(> :not(button))) {
width: fit-content;
border: 2px solid green;
}И разметка:
<div role="group">
<button type="button">Action 1</button>
<button type="button">Action 2</button>
<button type="button">Action 3</button>
</div>
Абсолютно нечитаемое месиво из селекторов, но оно работает. Вся магия кроется в сочетании
:has(), :not() и :nth-child(). Что там вообще происходит? Мы говорим:1) выбери элемент с атрибутом
role="group"2) внутри которого вторым дочерним элементом является кнопка
3) и внутри которого нет дочерних элементов, которые не являются кнопкой
Иными словами: выбери группу, в которой есть как минимум две кнопки и нет ничего кроме кнопок.
Перекладывая эту идею на табы, можно получить такой селектор:
[role="tablist"]:has(> [role="tab"]:nth-child(2)):not(:has(> :not([role="tab"]))) {
/* стили */
}🤯5👍1
Дополнение к предыдущему посту
Зачем вообще писать такие монструозные селекторы? Их невозможно читать, они обладают высокой специфичностью и противоречат общепринятым подходам к неймингу. Какая в этом может быть практическая польза?
Поиск подходящих элементов
Допустим, разрабатывается скрипт. Этот скрипт должен добавлять поведение в разметку. Для правильной работы скрипта нужна определённая структура, классы и атрибуты. Можно, найти корневой элемент, проверить его атрибуты, затем получить дочерние элементы и проверить их. Для этого придётся писать много JavaScript с
Проверка элементов
Бывают задачи, когда разметка вставляется извне и её нужно проверить и что-то сделать на основе этого. Например, вставка разметки из WYSIWYG-редактора, передача элементов в Shadow DOM через слоты, композиция элементов и т.д. Как и в предыдущем примере, можно проходиться по дереву и производить проверки. В качестве альтернативы, можно использовать метод
Classless библиотеки
Экзотичный, но всё же существующий подход. Его суть в том, чтобы написать таблицу стилей, которая не содержит селекторов по классу, полагается на семантические элементы, атрибуты, сочетания элементов и вложенность. Вполне себе решение для оформления демок, простых страниц, возможно даже документации. Примеры таких таблиц стилей:
- Water.css
- Simple.css
- matcha.css
- pico.css
- new.css
- и другие
Отладка вёрстки
Если взять хорошие практики HTML, найти несоответствующую им разметку с помощью сложных селекторов и подсвечивать броским цветом такую разметку, то получится интересный инструмент для отладки вёрстки в браузере. Хейдон Пикеринг ещё в 2013 году сделал подобную библиотеку REVENGE.CSS, в 2016 году выступил с докладом об этом, а в 2024 году переосмыслил идеи под новые возможности CSS и написал статью об этом у себя в блоге.
Тестирование вёрстки
Идею из предыдущего абзаца можно завернуть в JavaScript, который затем запускать в браузере, IDE, на CI/CD или в Storybook. Получится своеобразный линтер и набор тестов для разметки. Можно дописать специфические для компонентов сложные селекторы и отслеживать, что все атрибуты и дочерние элементы на месте, они правильно вложены и нет ничего лишнего. Если что-то изменится, то компонент перестанет соответствовать селектору, значит тест не пройден.
Потому что CSS так может
Действительно, а почему бы и нет? Это современный CSS, который работает во всех актуальных версиях браузеров. Полезно потренироваться и знать, что CSS так в принципе может. Вполне возможно, что в какой-то ситуации эти знания пригодятся и помогут решить задачу на реальном проекте, сделать демку на Codepen, уменьшить количество проверок и условий в JavaScript. Это как регулярные выражения, но в CSS. А регулярные выражения полезны и, порой, незаменимы, хотя выглядят как месиво из случайных символов.
Зачем вообще писать такие монструозные селекторы? Их невозможно читать, они обладают высокой специфичностью и противоречат общепринятым подходам к неймингу. Какая в этом может быть практическая польза?
Поиск подходящих элементов
Допустим, разрабатывается скрипт. Этот скрипт должен добавлять поведение в разметку. Для правильной работы скрипта нужна определённая структура, классы и атрибуты. Можно, найти корневой элемент, проверить его атрибуты, затем получить дочерние элементы и проверить их. Для этого придётся писать много JavaScript с
if-ами и перемещаться по DOM. Вместо этого, при помощи метода querySelector() и сложного селектора, можно сразу получить нужный элемент, который удовлетворяет всем условиям.Проверка элементов
Бывают задачи, когда разметка вставляется извне и её нужно проверить и что-то сделать на основе этого. Например, вставка разметки из WYSIWYG-редактора, передача элементов в Shadow DOM через слоты, композиция элементов и т.д. Как и в предыдущем примере, можно проходиться по дереву и производить проверки. В качестве альтернативы, можно использовать метод
matches() со сложным селектором и проверять элементы на соответствие.Classless библиотеки
Экзотичный, но всё же существующий подход. Его суть в том, чтобы написать таблицу стилей, которая не содержит селекторов по классу, полагается на семантические элементы, атрибуты, сочетания элементов и вложенность. Вполне себе решение для оформления демок, простых страниц, возможно даже документации. Примеры таких таблиц стилей:
- Water.css
- Simple.css
- matcha.css
- pico.css
- new.css
- и другие
Отладка вёрстки
Если взять хорошие практики HTML, найти несоответствующую им разметку с помощью сложных селекторов и подсвечивать броским цветом такую разметку, то получится интересный инструмент для отладки вёрстки в браузере. Хейдон Пикеринг ещё в 2013 году сделал подобную библиотеку REVENGE.CSS, в 2016 году выступил с докладом об этом, а в 2024 году переосмыслил идеи под новые возможности CSS и написал статью об этом у себя в блоге.
Тестирование вёрстки
Идею из предыдущего абзаца можно завернуть в JavaScript, который затем запускать в браузере, IDE, на CI/CD или в Storybook. Получится своеобразный линтер и набор тестов для разметки. Можно дописать специфические для компонентов сложные селекторы и отслеживать, что все атрибуты и дочерние элементы на месте, они правильно вложены и нет ничего лишнего. Если что-то изменится, то компонент перестанет соответствовать селектору, значит тест не пройден.
Потому что CSS так может
Действительно, а почему бы и нет? Это современный CSS, который работает во всех актуальных версиях браузеров. Полезно потренироваться и знать, что CSS так в принципе может. Вполне возможно, что в какой-то ситуации эти знания пригодятся и помогут решить задачу на реальном проекте, сделать демку на Codepen, уменьшить количество проверок и условий в JavaScript. Это как регулярные выражения, но в CSS. А регулярные выражения полезны и, порой, незаменимы, хотя выглядят как месиво из случайных символов.
👍4🤓1
Подключение шрифтов
Иногда в исходниках проектов, даже свежих, можно обнаружить примерно такой код:
Такой сниппет может повторяться для каждого семейства шрифта, толщины и стиля. Сопровождается это папкой
Но подобный сниппет уже устарел, сейчас нет необходимости в таком количестве разных шрифтов. Далее ряд рекомендаций по подключению шрифтов.
1) не используйте
2) достаточно формата
3) указывайте одинаковое имя семейства в
4) указывайте способ отображения шрифта. В
5) не подключайте шрифты с Google Fonts через
6) создавайте подмножества (subsetting) шрифтов в сочетании со свойством
7) подключайте основной шрифт в HTML при помощи
8) предварительно загрузите основной шрифт при помощи
9) используйте вариативные шрифты. Файл с вариативным шрифтом хоть и весит больше, но если вариаций шрифта слишком много, то вариативный шрифт обеспечит выигрыш по размеру.
Также ссылки для чтения:
- Best practices for fonts
- Optimize web fonts
- Статьи Зака Лезермана про шрифты
Иногда в исходниках проектов, даже свежих, можно обнаружить примерно такой код:
@font-face {
font-family: 'Roboto Regular';
font-style: normal;
font-weight: 400;
src: local('Roboto'),
url('roboto-regular.eot?#iefix') format('embedded-opentype'),
url('roboto-regular.woff2') format('woff2'),
url('roboto-regular.woff') format('woff'),
url('roboto-regular.ttf') format('truetype'),
url('roboto-regular.noscript#Roboto') format('noscript');
}Такой сниппет может повторяться для каждого семейства шрифта, толщины и стиля. Сопровождается это папкой
fonts с десятом шрифтов разных форматов. Ноги растут из онлайн-генераторов, например, шрифтобелки. На вход поступают шрифты в формате ttf. Далее происходят тонкие настройки, смысл которых понимают только специалисты по шрифтам. На выходе получается архив с готовым CSS и той самой папкой fonts. Это удобно, потому что руками так делать не хочется.Но подобный сниппет уже устарел, сейчас нет необходимости в таком количестве разных шрифтов. Далее ряд рекомендаций по подключению шрифтов.
1) не используйте
local(). Эта функция пытается найти зарегистрированный в операционной системе шрифт и использовать его. На первый взгляд хорошая идея: экономим трафик, не ходим в сеть, переиспользуем ресурсы, быстрее отображаем текст. На практике же с local() много проблем. Шрифт может быть зарегистрирован под другим названием, на устройстве может быть другая версия шрифта, также локальные шрифты используются для фингерпринтинга.2) достаточно формата
woff2. Времена, когда нужны шрифты разных форматов, уже прошли. Все браузеры умеют работать с woff2. На данный момент это самый эффективный формат шрифта для веба, который должен использоваться по умолчанию. Если нужно поддерживать IE, то к woff2 можно добавить woff. Но не нужно генерировать, хранить и подключать noscript, eot, ttf и другие менее эффективные и старые форматы.3) указывайте одинаковое имя семейства в
font-family и разные значения font-weight и font-style. Не нужно называть шрифт одного семейства разными именами, например 'Roboto Regular' и 'Roboto Bold'. Назовите оба 'Roboto', а в font-weight и font-style отразите различия. Браузер сам определит, какой шрифт применить, без необходимости каждый раз указывать font-family.4) указывайте способ отображения шрифта. В
@font-face укажите свойство font-display со значением swap, optional или fallback, в зависимости от целей. Это важно для увеличения скорости загрузки, предотвращения сдвигов макета и общего восприятия загрузки сайта. 5) не подключайте шрифты с Google Fonts через
<link>. Сгенерируйте шрифт в Google Fonts, скачайте их локально и взьмите сгенерированные сниппеты CSS.6) создавайте подмножества (subsetting) шрифтов в сочетании со свойством
unicode-range. Если язык сайта русский, то нет смысла держать в шрифте многие латинские, японские, китайские и прочие глифы. Для этого шрифт можно разбить на несколько более мелких. В одном оставить кириллицу, цифры и знаки препинания, в другой вынести латиницу и всё остальное. Затем указать это в свойстве unicode-range и браузер скачает только тот шрифт, символы из которого есть на странице. Сам файл при этом будет весить меньше.7) подключайте основной шрифт в HTML при помощи
<style>. Так браузер обнаружит шрифт сразу при получении HTML страницы и не будет ждать загрузки и обработки CSS. Шрифт загрузится и применится раньше. Это позволит избежать вспышек нестилизованного текста (FOUT).8) предварительно загрузите основной шрифт при помощи
<link rel="preload" as="font" format="font/woff2" crossorigin>. Браузер начнёт загрузку шрифта заранее, ещё до того, как фактически обнаружит ссылку. В итоге шрифт частично или полностью будет загружен к моменту его обнаружения. Это также позволяет бороться с FOUT.9) используйте вариативные шрифты. Файл с вариативным шрифтом хоть и весит больше, но если вариаций шрифта слишком много, то вариативный шрифт обеспечит выигрыш по размеру.
Также ссылки для чтения:
- Best practices for fonts
- Optimize web fonts
- Статьи Зака Лезермана про шрифты
🔥6👍2👀2
You don't know HTML: input.showPicker()
Фича из опроса State Of HTML 2023 —
Метод
В примере кода видно, что с помощью
Этот метод позволяет прятать стандартные поля ввода, но вызывать их функции в виде системных пикеров. Особенно это актуально для для разработки кастомных полей для загрузки файлов на основе
#ydkhtml
Фича из опроса State Of HTML 2023 —
input.showPicker(). Это выглядит как JavaScript-метод (так оно и есть), может возникнуть вопрос: причём тут HTML? На самом деле этот метод описан именно в стандарте HTML. Это маленькое, но полезное улучшение для элементов форм.Метод
showPicker() предназначен для программного вызова системных пикеров. Метод доступен у элемента <input> с типами date, month, week, time, datetime-local, color, file, у полей с атрибутом autocomplete, у полей с атрибутом list в сочетании с элементом <datalist> и у <select>. При вызове метода отображается стандартный системный попап для выбора значения, как если бы пользователь нажал на поле самостоятельно.<input type="file">
<button type="button">Upload File</button>
<noscript>
const button = document.querySelector('button');
const input = document.querySelector('input');
button.addEventListener('click', () => {
try {
input.showPicker();
} catch (error) {
// Обработка ошибок
}
});
</noscript>
В примере кода видно, что с помощью
try-catch перехватываются исключения. Метод выбросит исключение NotAllowedError, если пользователь как-либо не взаимодействовал со страницей: скролил, кликал. Это сделано из соображений приватности. Если поле нельзя изменять, например оно в состоянии disabled или readonly, будет выброшено исключение InvalidStateError. Если элемент <select> не отображается на экране, будет выброшено исключение NotSupportedError. И если домен не same origin, то выбрасывается исключение SecurityError.Этот метод позволяет прятать стандартные поля ввода, но вызывать их функции в виде системных пикеров. Особенно это актуально для для разработки кастомных полей для загрузки файлов на основе
<input type="file">.#ydkhtml
👍7🔥4
5 правил ARIA
Accessible Rich Internet Application, или же сокращённо ARIA — это расширение HTML, предоставляющее набор атрибутов для расширения семантики HTML и разработки доступных сайтов и приложений.
Существует документ под названием Using ARIA, в котором даны рекомендации и описаны 5 правил использования ARIA.
Первое правило
Используйте встроенные в HTML элементы и атрибуты для передачи нужной семантики вместо использования ARIA. Иными словами: первое правило ARIA — не используйте ARIA.
Второе правило
Не меняйте семантику встроенных элементов без острой необходимости.
Вместо этого:
Лучше сделать так:
Третье правило
Все интерактивные элементы должны управляться с клавиатуры. Если вы создаёте интерактивный компонент, который нажимается, перетаскивается, пролистывается или прокручивается, то должна быть возможность делать это при помощи клавиатуры.
Скрипт должен реагировать на нажатие отдельных клавиш или их сочетаний при взаимодействии с компонентом.
Четвёртое правило
Не используйте
Не делайте так:
Или так:
Или так:
Пятое правило
У всех интерактивных элементов должно быть имя. Это имя должно быть указано одним из доступных способов (
Accessible Rich Internet Application, или же сокращённо ARIA — это расширение HTML, предоставляющее набор атрибутов для расширения семантики HTML и разработки доступных сайтов и приложений.
Существует документ под названием Using ARIA, в котором даны рекомендации и описаны 5 правил использования ARIA.
Первое правило
Используйте встроенные в HTML элементы и атрибуты для передачи нужной семантики вместо использования ARIA. Иными словами: первое правило ARIA — не используйте ARIA.
Второе правило
Не меняйте семантику встроенных элементов без острой необходимости.
Вместо этого:
<h2 role="tab">heading tab</h2>
Лучше сделать так:
<div role="tab">
<h2>heading tab</h2>
</div>
Третье правило
Все интерактивные элементы должны управляться с клавиатуры. Если вы создаёте интерактивный компонент, который нажимается, перетаскивается, пролистывается или прокручивается, то должна быть возможность делать это при помощи клавиатуры.
Скрипт должен реагировать на нажатие отдельных клавиш или их сочетаний при взаимодействии с компонентом.
Четвёртое правило
Не используйте
role="presentation" (синоним role="none") и aria-hidden="true" на интерактивных элементах.Не делайте так:
<button role="presentation">
press me
</button>
Или так:
<button aria-hidden="true">
press me
</button>
Или так:
<div aria-hidden="true">
<button>press me</button>
</div>
Пятое правило
У всех интерактивных элементов должно быть имя. Это имя должно быть указано одним из доступных способов (
<label>, aria-label, aria-labelledby и т.д.)👍6🔥4❤2💯2
Что на счёт элемента <denoscription>?
Таким вопросом задалась Сара Суиден в твиттере. В HTML есть элемент
Почему бы не добавить аналогичную возможность для указания
Элемент создаёт привязку с описанием, которое будет озвучиваться программами чтения с экрана, если эта функция включена. Это позволит следовать правилу "не использовать ARIA".
Таким вопросом задалась Сара Суиден в твиттере. В HTML есть элемент
<label for>, с помощью которого можно задать имя встроенным элементам <input>, <textarea>, <select>, <button>, <meter>, <progress>, <output> и FACE (Form-associated Custom Elements). Если у элементов не заданы атрибуты aria-label и aria-labelledby, то текст из <label> используется как имя.Почему бы не добавить аналогичную возможность для указания
aria-denoscription/aria-describedby? На данный момент нет способа сделать это без ARIA. С новым элементом это может выглядеть так:<label for="password">Пароль</label>
<input type="password" name="password" id="password">
<denoscription for="password">Пароль должен содержать не менее 8 символов, а также включать как минимум одну цифру, одну букву и один символ пунктуации.</denoscription>
Элемент создаёт привязку с описанием, которое будет озвучиваться программами чтения с экрана, если эта функция включена. Это позволит следовать правилу "не использовать ARIA".
👍6🤔1
Classless CSS
CSS-библиотеки почти всегда полагаются на классы. Сразу на ум приходит классический представитель такого подхода — Bootstrap. Есть и другие: Bulma, UIKit, Foundation и т.д.
Но есть подход под названием classless. Идея в том, чтобы стилизовать стандартные элементы и некоторые их сочетания (вложенность, соседство, положение в дереве) с помощью селекторов типа. То есть при таком подходе библиотека не содержит классов вовсе или содержит крайне ограниченное их количество.
На моё удивление, таких библиотек достаточно много. Есть простые реализации, напоминающие улучшенный normalize.css. Они стилизуют базовые элементы HTML, чтобы голая страница выглядела более-менее симпатично, лучше, чем со стандартными стилями браузера.
Есть и продвинутые реализации. Они предлагают базовую раскладку страницы и некоторые компоненты. Например,
Вот два источника с примерами classless библиотек: github-репозиторий и сайт cssbed. Думаю, в интернете можно найти еще что-то подобное.
Вопрос, который может возникнуть: зачем такие библиотеки нужны? Вот несколько примеров использования:
- прототипирование
- создание тестовых, отладочных и служебных страниц
- более красивые демки для образовательных целей
- быстрое создание простого сайта-визитки, портфолио, блога, документации
- создание стилизованных страниц, сгенерированных из Markdown
- альтернатива normalize/reset
- основа для создания своей библиотеки или темы
В общем, применимая штука. Тем более, что для работы достаточно просто вставить
CSS-библиотеки почти всегда полагаются на классы. Сразу на ум приходит классический представитель такого подхода — Bootstrap. Есть и другие: Bulma, UIKit, Foundation и т.д.
Но есть подход под названием classless. Идея в том, чтобы стилизовать стандартные элементы и некоторые их сочетания (вложенность, соседство, положение в дереве) с помощью селекторов типа. То есть при таком подходе библиотека не содержит классов вовсе или содержит крайне ограниченное их количество.
На моё удивление, таких библиотек достаточно много. Есть простые реализации, напоминающие улучшенный normalize.css. Они стилизуют базовые элементы HTML, чтобы голая страница выглядела более-менее симпатично, лучше, чем со стандартными стилями браузера.
Есть и продвинутые реализации. Они предлагают базовую раскладку страницы и некоторые компоненты. Например,
<nav> с нумерованным списком <ol> с ссылками <a> внутри <li> будет выглядеть как хлебные крошки. В таких библиотеках используются более сложные селекторы с комбинаторами и иногда :has(), но всё ещё без классов.Вот два источника с примерами classless библиотек: github-репозиторий и сайт cssbed. Думаю, в интернете можно найти еще что-то подобное.
Вопрос, который может возникнуть: зачем такие библиотеки нужны? Вот несколько примеров использования:
- прототипирование
- создание тестовых, отладочных и служебных страниц
- более красивые демки для образовательных целей
- быстрое создание простого сайта-визитки, портфолио, блога, документации
- создание стилизованных страниц, сгенерированных из Markdown
- альтернатива normalize/reset
- основа для создания своей библиотеки или темы
В общем, применимая штука. Тем более, что для работы достаточно просто вставить
<link> в <head> и всё будет работать. У меня даже возникла идея сделать свою реализацию classless-библиотеки 🤔🔥8👍2
Как я перестал верить технологиям
Рекомендую к просмотру доклад Алексея Симоненко "Как я перестал верить технологиям". Это один из моих любимых докладов. Не смотря на то, что он 2016 года, он всё ещё актуален. Примеры кода из 2016 года могут выглядеть странно, но в этом докладе важен не код, а суть.
Основные тезисы доклада:
- Мы любим решать сложные задачи и не любим доводить дело до конца
- Выбор модных технологий не даёт никаких преимуществ новому продукту
- Самое важное — это продукт, а не технологии
- Делайте продукты для людей, вместо возьни с технологиями
Приятного просмотра!
Рекомендую к просмотру доклад Алексея Симоненко "Как я перестал верить технологиям". Это один из моих любимых докладов. Не смотря на то, что он 2016 года, он всё ещё актуален. Примеры кода из 2016 года могут выглядеть странно, но в этом докладе важен не код, а суть.
Основные тезисы доклада:
- Мы любим решать сложные задачи и не любим доводить дело до конца
- Выбор модных технологий не даёт никаких преимуществ новому продукту
- Самое важное — это продукт, а не технологии
- Делайте продукты для людей, вместо возьни с технологиями
Приятного просмотра!
YouTube
Алексей Симоненко — Как я перестал верить технологиям
Подробнее о конференции HolyJS: https://jrg.su/EM4wwV
— —
Алексей Симоненко Как я перестал верить технологиям
JavaScript конференция HolyJS 2016 Piter
Санкт-Петербург, 05.06.2016
Постоянная смена технологий почему её стоит избегать.
— —
Алексей Симоненко Как я перестал верить технологиям
JavaScript конференция HolyJS 2016 Piter
Санкт-Петербург, 05.06.2016
Постоянная смена технологий почему её стоит избегать.
👍6🔥4
Баги в Chrome
Обычно Chrome выступает в роли эталонного браузера, в котором всё работает. Поэтому сейчас модно жаловаться на Safari и иногда Firefox за баги и отсутствие поддержки некоторых фич.
Но за последние две недели я дважды столкнулся с багами в Chrome, тогда как в других браузерах (Firefox и Safari) все работало как нужно. Ничто не идеально. В таком сложном ПО, как браузеры, есть огромное количество багов. Во всех из них. И браузеры работают сообща над их исправлением в рамках инициативы Interop.
Отдельно хочу сказать про "Safari — новый IE". Кажется, некоторые современные разработчики забывают о таком понятии, как кроссбраузерность. Это всё ещё актуально. Задача разработчика, который делает веб-интерфейс, позаботиться о том, чтобы он выглядел и работал одинаково во всех целевых браузерах.
Кроссбраузерность — это навык, которым должен обладать профессиональный разработчик. Тем более, что сейчас ситуация обстоит намного лучше: есть Can I Use, Baseline, Web Platform Status, уже упомянутый Interop, Browserslist, Autoprefixer и прочие инструменты.
Обычно Chrome выступает в роли эталонного браузера, в котором всё работает. Поэтому сейчас модно жаловаться на Safari и иногда Firefox за баги и отсутствие поддержки некоторых фич.
Но за последние две недели я дважды столкнулся с багами в Chrome, тогда как в других браузерах (Firefox и Safari) все работало как нужно. Ничто не идеально. В таком сложном ПО, как браузеры, есть огромное количество багов. Во всех из них. И браузеры работают сообща над их исправлением в рамках инициативы Interop.
Отдельно хочу сказать про "Safari — новый IE". Кажется, некоторые современные разработчики забывают о таком понятии, как кроссбраузерность. Это всё ещё актуально. Задача разработчика, который делает веб-интерфейс, позаботиться о том, чтобы он выглядел и работал одинаково во всех целевых браузерах.
Кроссбраузерность — это навык, которым должен обладать профессиональный разработчик. Тем более, что сейчас ситуация обстоит намного лучше: есть Can I Use, Baseline, Web Platform Status, уже упомянутый Interop, Browserslist, Autoprefixer и прочие инструменты.
Caniuse
Can I use... Support tables for HTML5, CSS3, etc
"Can I use" provides up-to-date browser support tables for support of front-end web technologies on desktop and mobile web browsers.
🔥5❤3🤝3
property и starting-style
Вышел Firefox 128, а вместе с ним во всех стабильных браузерах теперь доступны директивы
property
Директива
Определяется пользовательское свойство
starting-style
Директива
Или с использованием вложенности:
Когда поповер отобразится, свойства
Вышел Firefox 128, а вместе с ним во всех стабильных браузерах теперь доступны директивы
@property и @starting-style.property
Директива
@property позволяет управлять характеристиками пользовательских свойств. А именно: типом, наследованием и значением по умолчанию.@property --width {
syntax: "<length>";
inherit: false;
initial-value: 48px;
}Определяется пользовательское свойство
--width, его значение будет преобразовано к типу <length>, оно не будет наследоваться и по умолчанию будет равно 48px. Это свойство можно будет использовать для анимации в @keyframes. Подробнее о @property.starting-style
Директива
@starting-style даёт возможность задавать стили, которые будут применены при отрисовке элемента, когда значение display меняется с none на другое значение. С помощью этого механизма можно анимировать появление элемента.[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
}
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}Или с использованием вложенности:
[popover]:popover-open {
opacity: 1;
transform: scaleX(1);
@starting-style {
opacity: 0;
transform: scaleX(0);
}
}Когда поповер отобразится, свойства
opacity и transform плавно изменят свои значения. Подробнее о @starting-style.Firefox
Firefox 128.0, See All New Features, Updates and Fixes
🔥11
Уточнение про starting-style
В предыдущем посте я писал, что с выходом Firefox 128,
Перечитывая релиз ноуты Firefox 128 я не обнаружил там информации о
В действительности,
На данный момент релиз запланирован на 129 версию, во всяком случае в релиз ноутах беты есть информация о
В предыдущем посте я писал, что с выходом Firefox 128,
@property и @starting-style теперь доступны во всех стабильных браузерах. Я написал об этом на основании того, что видел новость о добавлении @starting-style в Firefox.Перечитывая релиз ноуты Firefox 128 я не обнаружил там информации о
@starting-style, поэтому решил уточнить этот момент.В действительности,
@starting-style доступен с Firefox 127, но за специальным флагом и ещё не до конца реализован. Поэтому эта директива всё ещё не стала кроссбраузерной и она не доступна в Firefox 128.На данный момент релиз запланирован на 129 версию, во всяком случае в релиз ноутах беты есть информация о
@starting-style. Но не всё из беты может попасть в финальный релиз, поэтому на самом деле не известно, когда это заедет.👍5
You don't know HTML: Media Capture
HTML Media Capture — небольшое расширение для форм, которое позволяет использовать аудио/видео устройства для получения данных и их дальнейшей загрузки.
У мобильных устройств есть основная и фронтальная камеры, а также микрофон. Почему бы не использовать эти возможности для получения контента? Например, на сайте есть функция смены аватара пользователя. Можно использовать камеру устройства, чтобы сделать снимок и сразу же его загрузить.
Чтобы захватить данные с аудио/видео устройств, нужно добавить атрибуты
Если нужно захватить видео на основную камеру, то нужно установить
Можно также получить записанный файл из
В общем, небольшая фича, которая может быть полезна в некоторых ситуациях для улучшения пользовательского опыта. Пользователю не придётся сворачивать сайт, включать камеру, выбирать режим, делать фото, возвращаться на сайт и искать фото через диалог выбора файла.
#ydkhtml
HTML Media Capture — небольшое расширение для форм, которое позволяет использовать аудио/видео устройства для получения данных и их дальнейшей загрузки.
У мобильных устройств есть основная и фронтальная камеры, а также микрофон. Почему бы не использовать эти возможности для получения контента? Например, на сайте есть функция смены аватара пользователя. Можно использовать камеру устройства, чтобы сделать снимок и сразу же его загрузить.
<form action="/user/change-avatar" method="post" enctype="multipart/form-data">
<label for="avatar">Take a photo</label>
<input type="file" id="avatar" accept="image/*" capture="user">
<button>Send</button>
</form>
Чтобы захватить данные с аудио/видео устройств, нужно добавить атрибуты
capture и accept для <input type="file">. В примере мы говорим браузеру, что хотим использовать фронтальную камеру устройства (capture="user"), чтобы сделать фото (accept="image/*"). При нажатии на поле, вместо стандартного окна выбора файла, запустится приложение камеры в режиме съемки на фронтальную камеру. После снимка, файл изображения будет помещён в поле выбора файла и форму можно будет отправить на сервер.Если нужно захватить видео на основную камеру, то нужно установить
accept="video/*" capture="environment", для записи аудио — accept="audio/*" capture. Само собой, нужно дать браузеру доступ к камере и микрофону, иначе не заработает.Можно также получить записанный файл из
<input> через Javanoscript и нарисовать его в <canvas>, вставить в <img>, <audio> или <video> для предпросмотра перед отправкой. Можно отправить данные на сервер при помощи Fetch API.В общем, небольшая фича, которая может быть полезна в некоторых ситуациях для улучшения пользовательского опыта. Пользователю не придётся сворачивать сайт, включать камеру, выбирать режим, делать фото, возвращаться на сайт и искать фото через диалог выбора файла.
#ydkhtml
👍13🔥3
Условно адаптивно
Подход к организации стилей, который предложил Вадим Макеев в одном из своих докладов.
Как мы обычно пишем стили:
Это может быть подход Desktop First с
Суть в том, что:
- медиа-запросы каскадно переопределяют все предыдущие
- все стили склеиваются в один бандл, который подключается к странице.
Вадим предлагает другой подход:
- разделить стили по файлам на базовые и под конкретные группы экранов
- ограничить стили под группы экраны так, чтобы не было пересечений
Как это выглядит:
Базовые стили применяются всегда. Атрибут
Стили для мобильных применяются на экранах с шириной до
В итоге стили под разные группы экранов не конфликтуют между собой, потому что
Важно ещё отметить, что такой подход обеспечивает прирост производительности. CSS — ресурс, блокирующий отрисовку. Браузеру нужны стили, чтобы отрисовать страницу. При использовании атрибута
Есть и минусы. Например, если что-то на десктопе выглядит одним образом, а на планшетах и мобильных выглядит другим образом, то придётся дублировать одинаковые стили и для планшетов и для мобильных. Это можно решить выносом таких правил в базовые стили. Также такой подход требует больше ручной работы. Инструментов для автоматизации всего процесса на данный момент нет, только отдельные плагины для PostCSS.
На одном из своих проектов я использовал этот подход и он мне в целом понравился. Рекомендую посмотреть доклад с более подробным объяснением идеи.
Подход к организации стилей, который предложил Вадим Макеев в одном из своих докладов.
Как мы обычно пишем стили:
.element {
/* стили */
}
@media (max-width: 1024px) {
.element {
/* стили для экранов шириной 1024px и меньше */
}
}
@media (max-width: 768px) {
.element {
/* стили для экранов шириной 768px и меньше */
}
}Это может быть подход Desktop First с
max-width или Mobile First с min-width. Всё это может быть написано в одном файле или распределено по разным файлам и склеено в процессе сборки. Это может быть нативный CSS или SCSS. Не важно.Суть в том, что:
- медиа-запросы каскадно переопределяют все предыдущие
- все стили склеиваются в один бандл, который подключается к странице.
Вадим предлагает другой подход:
- разделить стили по файлам на базовые и под конкретные группы экранов
- ограничить стили под группы экраны так, чтобы не было пересечений
Как это выглядит:
<head>
<!-- ... -->
<link rel="stylesheet" href="base.css" media="all">
<link rel="stylesheet" href="mobile.css" media="(width < 768px)">
<link rel="stylesheet" href="tablet.css" media="(768px <= width < 1024px)">
<link rel="stylesheet" href="desktop.css" media="(width >= 1024px)">
<!-- ... -->
</head>
Базовые стили применяются всегда. Атрибут
media="all" можно не указывать, но пусть будет для наглядности. К базовыми стилями относятся те, которые применяются вне зависимости от экрана. Это могут быть директивы @font-face, сбросы, общие стили и т.д.Стили для мобильных применяются на экранах с шириной до
768px. Планшетные стили применяются на экранах шириной от 768px, до 1024px не включая. Десктопные стили применяются на экранах от 1024px и выше. В примере используется Media Query Range Syntax, который уже неплохо поддерживается.В итоге стили под разные группы экранов не конфликтуют между собой, потому что
media взаимоисключающие. Во вкладке Styles в DevTools не будет каскада переопределений, это улучшает читаемость, упрощает отдадку и не заставляет отменять правила. Также всегда понятно, где искать нужные стили в проекте.Важно ещё отметить, что такой подход обеспечивает прирост производительности. CSS — ресурс, блокирующий отрисовку. Браузеру нужны стили, чтобы отрисовать страницу. При использовании атрибута
media у <link>, браузер проверяет медиа-запрос на соответствие. Если он соответствует параметрам, файл загружается как обычно. А вот если не соответствует, то, вопреки ожиданиям, он всё равно загружается, но с более низким приоритетом и, что самое главное, не блокирует отрисовку. В итоге стили загружаются и применяются быстрее, а значит отрисовка тоже происходит быстрее.Есть и минусы. Например, если что-то на десктопе выглядит одним образом, а на планшетах и мобильных выглядит другим образом, то придётся дублировать одинаковые стили и для планшетов и для мобильных. Это можно решить выносом таких правил в базовые стили. Также такой подход требует больше ручной работы. Инструментов для автоматизации всего процесса на данный момент нет, только отдельные плагины для PostCSS.
На одном из своих проектов я использовал этот подход и он мне в целом понравился. Рекомендую посмотреть доклад с более подробным объяснением идеи.
YouTube
Условно адаптивно [ru] / Вадим Макеев
Видео с онлайн-конференции JavaScript fwdays'21, которая прошла с 1-8 июня 2021 года.
Описание доклада:
Кто-то делает сразу два сайта: мобильный и, видимо, стационарный. Принюхивается к браузеру и отдаёт подходящую версию. Что ж. Кто-то делает гибко и отдаёт…
Описание доклада:
Кто-то делает сразу два сайта: мобильный и, видимо, стационарный. Принюхивается к браузеру и отдаёт подходящую версию. Что ж. Кто-то делает гибко и отдаёт…
👍14
Baseline
Инициатива Baseline призвана помочь с определением кроссбраузерной поддержки фич веб-платформы. Baseline охватывает 4 основных браузера:
- Chrome (ПК и Android)
- Edge
- Firefox (ПК и Android)
- Safari (macOS и iOS)
Смысл в том, чтобы показать уровень поддержки фич веб-платформы в этих браузерах и устанавливать некую отметку, начиная с которой фичу можно использовать в проектах.
Данные Baseline можно увидеть на Can I Use, MDN, на ресурсах от производителей браузеров, а также на Web Platform Dashboard.
Каждая фича в рамках Baseline получает один из трёх статусов:
- Limited availability
- Newly available
- Widely available
Limited availability означает, что фича появилась в каком-то из браузеров или в нескольких из них, но не во всех. То есть ещё нет кроссбраузерной поддержки и фичу лучше не использовать в продакшине. Такие фичи помечаются оранжевым крестиком.
Newly available означает, что фича недавно появилась во всех Baseline-браузерах. Фичу можно использовать, при условии поддержки последних версий. Такие фичи помечаются синей галочкой.
Widely available означает, что фича внедрена во все браузеры уже достаточно давно, чтобы считаться широко поддерживаемой. Этот статус присваивается через 30 месяцев (2.5 года) после получения статуса Newly available. По мнению группы WebDX, этого срока достаточно, чтобы фичу можно было использовать без оглядки на её поддержку. Помечаются такие фичи зелёной галочкой.
Инициатива Baseline призвана помочь с определением кроссбраузерной поддержки фич веб-платформы. Baseline охватывает 4 основных браузера:
- Chrome (ПК и Android)
- Edge
- Firefox (ПК и Android)
- Safari (macOS и iOS)
Смысл в том, чтобы показать уровень поддержки фич веб-платформы в этих браузерах и устанавливать некую отметку, начиная с которой фичу можно использовать в проектах.
Данные Baseline можно увидеть на Can I Use, MDN, на ресурсах от производителей браузеров, а также на Web Platform Dashboard.
Каждая фича в рамках Baseline получает один из трёх статусов:
- Limited availability
- Newly available
- Widely available
Limited availability означает, что фича появилась в каком-то из браузеров или в нескольких из них, но не во всех. То есть ещё нет кроссбраузерной поддержки и фичу лучше не использовать в продакшине. Такие фичи помечаются оранжевым крестиком.
Newly available означает, что фича недавно появилась во всех Baseline-браузерах. Фичу можно использовать, при условии поддержки последних версий. Такие фичи помечаются синей галочкой.
Widely available означает, что фича внедрена во все браузеры уже достаточно давно, чтобы считаться широко поддерживаемой. Этот статус присваивается через 30 месяцев (2.5 года) после получения статуса Newly available. По мнению группы WebDX, этого срока достаточно, чтобы фичу можно было использовать без оглядки на её поддержку. Помечаются такие фичи зелёной галочкой.
🔥5
CSS Scroll Snap Module Level 2
23 июля CSSWG опубликовала первый черновик CSS Scroll Snap Module Level 2. Это дальнейшее развитие Scroll Snap.
Напомню, что CSS Scroll Snap — это спецификация про управление привязкой элементов внутри прокручиваемого контейнера. Например, при помощи этой спецификации можно сделать полноэкранную прокрутку страницы, как в плагине fullPage.js. Также при помощи этой спецификации, гридов и небольшого количества JavaScript реализована карусель в библиотеке компонентов Shoelace.
Module Level 2 расширяет спецификацию и добавляет новые возможности.
1) свойство
И разметка:
2) псевдоклассы
3) события
23 июля CSSWG опубликовала первый черновик CSS Scroll Snap Module Level 2. Это дальнейшее развитие Scroll Snap.
Напомню, что CSS Scroll Snap — это спецификация про управление привязкой элементов внутри прокручиваемого контейнера. Например, при помощи этой спецификации можно сделать полноэкранную прокрутку страницы, как в плагине fullPage.js. Также при помощи этой спецификации, гридов и небольшого количества JavaScript реализована карусель в библиотеке компонентов Shoelace.
Module Level 2 расширяет спецификацию и добавляет новые возможности.
1) свойство
scroll-snap-target для указания элемента, который изначально должен быть привязан:.carousel {
overflow-inline: auto;
}
.carousel .origin {
scroll-start-target: auto;
}И разметка:
<div class="carousel">
<img src="img1.jpg">
<img src="img2.jpg">
<img src="img3.jpg" class="origin">
<img src="img4.jpg">
<img src="img5.jpg">
</div>
2) псевдоклассы
:snapped-x, :snapped-y, :snapped-inline и :snapped-block для стилизации привязанных элементов. Однако, принято решение отказаться от них в пользу новых Style Container Queries.3) события
scrollsnapchange и scrollsnapchanging для отслеживания изменений привязанных элементов при прокрутке в JavaScript. Вместе с ними добавляется новый тип события SnapEvent с соответствующим интерфейсом и набором свойств.🔥2❤1
7го августа выступаю на MinskCSS с докладом про Shadow DOM! Приходите, начало в 19:00.
👍6🔥2
Forwarded from MinskCSS/MinskJS
✨ Продолжаем знакомить вас с докладами на MinskCSS Meetup #12.
Наш следующий спикер Алексей Назаренко расскажет про особенности Shadow DOM, связанные с изоляцией и стилями, и покажет, как с этим работать.
Место проведения:
👉 https://youtube.com/live/-s7s_IB2egc 👈
Описание и программа:
https://telegra.ph/MinskCSS-Meetup-12-07-29
Подписывайтесь, чтобы ничего не пропускать: Telegram | Twitter
Наш следующий спикер Алексей Назаренко расскажет про особенности Shadow DOM, связанные с изоляцией и стилями, и покажет, как с этим работать.
Место проведения:
👉 https://youtube.com/live/-s7s_IB2egc 👈
Описание и программа:
https://telegra.ph/MinskCSS-Meetup-12-07-29
Подписывайтесь, чтобы ничего не пропускать: Telegram | Twitter
🔥16