You don't know HTML: hidden
В HTML есть глобальный атрибут
Элементы скрываются по простой причине: атрибут
Если в стилях разработчика для элемента не указано свойство
Есть два способа предотвратить неожиданное поведение «атрибут есть, а элемент не скрыт». Первый — добавить в глобальные стили правило с
Второй способ — добавить правило для
Атрибут
На мой взгляд это удобнее, чем работать с инлайн-стилями или делать специальный атомарный класс.
Из-за того, что у браузеров есть стили для
Ещё одна особенность
Но если указать в качестве значения
Эта особенность полезна при разработке компонентов, которые скрывают контент, например раскрывающиеся блоки или аккордеоны. Есть статья с примером реализации аккордеонов и использованием
#ydkhtml
В HTML есть глобальный атрибут
hidden. Он скрывает элемент, у которого указан. Можно задать hidden без значения или продублировать название атрибута в его значении по правилам булевых атрибутов:<div hidden>
<!-- ... -->
</div>
<div hidden="hidden">
<!-- ... -->
</div>
Элементы скрываются по простой причине: атрибут
hidden реализован в браузерах как презентационный и к нему применяется соответствующее правило.[hidden] {
display: none;
}Если в стилях разработчика для элемента не указано свойство
display, то при добавлении атрибута hidden он будет скрыт. Если значение display в стилях разработчика указано, то оно переопределяет правило атрибута hidden, так как по каскаду стили разработчика переопределяют стили браузера.Есть два способа предотвратить неожиданное поведение «атрибут есть, а элемент не скрыт». Первый — добавить в глобальные стили правило с
!important. Это тот редкий случай, когда использование !important уместно:[hidden] {
display: none !important;
}Второй способ — добавить правило для
[hidden] у элементов, где планируется использовать атрибут. Можно сочетать с :where() для сохранения специфичности:.element {
display: flex;
}
.element:where([hidden]) {
display: none;
}Атрибут
hidden отражается в свойство hidden и наоборот. Поэтому в JS можно удобно переключать состояние видимости и не беспокоиться о значении свойства display.// управление через атрибут
element.setAttribute('hidden', '');
element.removeAttribute('hidden');
// управление через свойство
element.hidden = true;
element.hidden = false;
// проверка, скрыт ли элемент
if (element.hidden) {
//...
}
// переключение
element.hidden = !element.hidden;
На мой взгляд это удобнее, чем работать с инлайн-стилями или делать специальный атомарный класс.
// управление через свойство display
element.style.display = 'none';
// нужно помнить предыдущее состояние
element.style.display = 'flex';
// управление через атрибут style
element.setAttribute('style', 'display: none');
// можно удалить другие нужные инлайн-стили
element.removeAttribute('style');
// управление через утилитарный класс
element.classList.add('is-hidden');
element.classList.remove('is-hidden');
Из-за того, что у браузеров есть стили для
hidden, элемент можно скрыть изначально на уровне разметки. Не нужно ждать загрузки, обработки и применения стилей. Поэтому hidden может стать решением в тех ситуациях, когда при загрузке страницы скрытый контент на доли секунд виден из-за того, что стили не догрузились.Ещё одна особенность
hidden в том, что атрибут может принимать значения. То есть это одновременно булев и перечисляемый атрибут. Так сложилось исторически из-за обратной совместимости. Атрибут без значения, со значением в виде пустой строки, строки hidden и строки с не валидным значением трактуется браузером как если у элемента установлен атрибут без значения.<!-- варианты эквивалентны -->
<div hidden></div>
<div hidden=""></div>
<div hidden="hidden"></div>
<div hidden="invalid"></div>
Но если указать в качестве значения
until-found, поведение меняется. hidden="until-found" делает элемент скрытым до тех пор пока пользователь не воспользуется функцией поиска по странице. Если внутри элемента есть контент, попадающий под условия поиска, то элемент будет показан. Также отличается значение в стилях браузера.[hidden="until-found"] {
content-visibility: hidden;
}Эта особенность полезна при разработке компонентов, которые скрывают контент, например раскрывающиеся блоки или аккордеоны. Есть статья с примером реализации аккордеонов и использованием
hidden="until-found".#ydkhtml
Chrome for Developers
Making collapsed content accessible with hidden=until-found | CSS and UI | Chrome for Developers
How this new attribute value can ensure that content within accordion sections can be found and linked to.
❤18👍7🔥6
Menu elements
Я рассказывал про меню, его семантику, применение и различия с навигацией. Важно разделять меню команд и навигационное меню. Первое про вызов действий в контексте приложения, его части или выбранного объекта. Второе про набор ссылок для перехода между страницами.
Для реализации навигационного меню в HTML есть элементы
В OpenUI появилось предложение по добавлению в HTML новых элементов для создания меню команд.
Меню-флажок поддерживает псевдо-класс
Эти элементы в сочетании с Popover API, Focusgroup и Anchor Positioning позволят создавать меню команд как в рекомендациях ARIA, но без использования ARIA-атрибутов для передачи семантики и JS для реализации поведения клавиатуры и отображения выпадающих меню. Сами действия, вызываемые элементами меню, само собой, нужно определить в JS.
Предложение находится на ранней стадии. Есть несколько открытых вопросов по синтаксису, набору возможностей, именованию элементов и атрибутов, интеграции с другими существующими и предлагаемыми возможностями. Ожидаем в платформе новый примитив для меню.
#html #ui
Дисклеймер: это обзор раннего предложения новых функций веб-платформы. Синтаксис может измениться в будущем или от функции могут отказаться.
Я рассказывал про меню, его семантику, применение и различия с навигацией. Важно разделять меню команд и навигационное меню. Первое про вызов действий в контексте приложения, его части или выбранного объекта. Второе про набор ссылок для перехода между страницами.
Для реализации навигационного меню в HTML есть элементы
<nav>, <ol>, <ul>, <li> и <a>. Для реализации меню команд в HTML ничего нет, нужно использовать ARIA. Есть элемент <menu>, который по определению предназначен для команд. Но он просто заменяет список <ul> и не добавляет функциональности и нужной семантики.В OpenUI появилось предложение по добавлению в HTML новых элементов для создания меню команд.
<menubar> — контейнер для элементов меню с встроенной ролью menubar. Предназначен для создания основного меню приложения. Обычно меню располагается в верхней части интерфейса, отображается всегда, содержит горизонтальный список опций, которые раскрывают выпадающие подменю. <menulist> — контейнер для элементов меню с встроенной ролью menu. Предназначен для создания выпадающих меню и контекстных меню. Пункты меню, как правило, вызывают действия в приложении или раскрывают дополнительные уровни меню. <menuitem> — элемент меню, аналог кнопки для вызова действий или переключения подменю. Поддерживает атрибут disabled для отключения и псевдо-класс :disabled для стилизации. Может открывать подменю, если указан атрибут menu с идентификатором, как popover. Генерирует событие toggle, если переключает подменю.<menuitemcheckbox> — элемент меню, который работает как флажок. Подразумевает группу из нескольких связанных элементов для выбора дополняющих опций. Например, список отображаемых колонок таблицы или список активных панелей. Для группировки предлагается использовать элемент <fieldset>. Меню-флажок поддерживает псевдо-класс
:checked для стилизации выбранного состояния и псевдо-элемент ::checkmark для стилизации галочки. При нажатии генерирует события change и toggle. Может быть отключён атрибутом disabled и стилизован псевдо-классом :disabled.<menuitemradio> — элемент меню, который работает как радио-кнопка. В основном работает как <menuitemcheckbox>, по предназначен для выбора взаимоисключающих опций. Например, режим сортировки или отображения данных. Поддерживает те же псевдо-классы, псевдо-элементы, атрибуты и события, что и <menuitemcheckbox>.Эти элементы в сочетании с Popover API, Focusgroup и Anchor Positioning позволят создавать меню команд как в рекомендациях ARIA, но без использования ARIA-атрибутов для передачи семантики и JS для реализации поведения клавиатуры и отображения выпадающих меню. Сами действия, вызываемые элементами меню, само собой, нужно определить в JS.
Предложение находится на ранней стадии. Есть несколько открытых вопросов по синтаксису, набору возможностей, именованию элементов и атрибутов, интеграции с другими существующими и предлагаемыми возможностями. Ожидаем в платформе новый примитив для меню.
#html #ui
❤8👍3🔥3
CSS-хаки и здравый смысл
Обозревая новые функции CSS, я часто упоминаю, что они позволяют реализовать тот или иной интерфейс без лишнего JS. Например, карусели, select или аккордеоны. Иногда подход «без лишнего JS» доходит до крайностей, когда придумывают так называемые Pure CSS решения с хаками для замены JS.
В HTML и CSS есть ряд особенностей, которые можно использовать не по прямому назначению и добиваться интересных результатов:
- флажки и радио-кнопоки в сочетании с псевдо-классом
- якорные ссылки в сочетании с псевдо-классом
- псевдо-классы
На основе этого делают вкладки, карусели, аккордеоны, раскрывающиеся меню, диалоги, галереи и прочие компоненты. Есть сайт с примерами.
Я и сам когда-то делал дровер через флажок, многоуровневое меню на ховерах и прочее. Был страшно собой доволен, ведь я сделал работающий компонент без JS, круто! Сейчас я понимаю, что это не правильно.
Нужно различать CSS-хаки и реальные решения для интерфейcов на CSS. Флажок — это элемент формы для выбора опции, а не переключатель. Якорная ссылка — это способ навигации по странице, а не решение для вкладок и диалогов.
CSS-хаки изящны, но портят пользовательский опыт и доступность. Неочевидные возможности, сложные селекторы и хитрые свойства усложняют поддержку проекта. Хаки полагаются на структуру HTML, что делает решения хрупкими. Хорошо эту тему раскрыл Вадим Макеев в старом докладе «Чистый CSS для грязных трюков».
Но есть хорошие примеры использования HTML и CSS для реализации интерфейса. Предлагаю доклад Никиты Дубко и доклад Килиана Валкхофа. Оба про то, как с умом использовать современные возможности HTML и CSS для решения классических задач без JS и вреда пользовательскому опыту.
#html #css #ui
Обозревая новые функции CSS, я часто упоминаю, что они позволяют реализовать тот или иной интерфейс без лишнего JS. Например, карусели, select или аккордеоны. Иногда подход «без лишнего JS» доходит до крайностей, когда придумывают так называемые Pure CSS решения с хаками для замены JS.
В HTML и CSS есть ряд особенностей, которые можно использовать не по прямому назначению и добиваться интересных результатов:
- флажки и радио-кнопоки в сочетании с псевдо-классом
:checked и комбинаторами соседства;- якорные ссылки в сочетании с псевдо-классом
:target и элементами с атрибутом id;- псевдо-классы
:hover и :focus в сочетании с комбинаторами соседства.На основе этого делают вкладки, карусели, аккордеоны, раскрывающиеся меню, диалоги, галереи и прочие компоненты. Есть сайт с примерами.
Я и сам когда-то делал дровер через флажок, многоуровневое меню на ховерах и прочее. Был страшно собой доволен, ведь я сделал работающий компонент без JS, круто! Сейчас я понимаю, что это не правильно.
Нужно различать CSS-хаки и реальные решения для интерфейcов на CSS. Флажок — это элемент формы для выбора опции, а не переключатель. Якорная ссылка — это способ навигации по странице, а не решение для вкладок и диалогов.
CSS-хаки изящны, но портят пользовательский опыт и доступность. Неочевидные возможности, сложные селекторы и хитрые свойства усложняют поддержку проекта. Хаки полагаются на структуру HTML, что делает решения хрупкими. Хорошо эту тему раскрыл Вадим Макеев в старом докладе «Чистый CSS для грязных трюков».
Но есть хорошие примеры использования HTML и CSS для реализации интерфейса. Предлагаю доклад Никиты Дубко и доклад Килиана Валкхофа. Оба про то, как с умом использовать современные возможности HTML и CSS для решения классических задач без JS и вреда пользовательскому опыту.
#html #css #ui
👍17❤3🔥3
Актуальные фавиконки
Самый простой способ добавить фавиконку на сайт — поместить файл
Многие пользуются генераторами фавиконок. Потому что нужны файлы для разных сценариев и проще закинуть генератору исходник и получить готовый результат, чем делать всё руками.
Проблема генераторов в том, что они отдают архив с десятком фавиконок в разных форматах и размерах, а также полотно кода, который нужно вставить в
-
-
-
Если сайт должен устанавливаться и работать как PWA, то к этому нужно добавить ещё четыре файла:
-
-
-
-
В статье от Злых Марсиан подробно объясняется, какие файлы использовать, как их подготовить и подключить к странице. Статья обновляется ежегодно, поэтому рекомендую периодически к ней возвращаться.
Не тащите в проекты гору устаревших фавиконок и не захламляйте
#html
Самый простой способ добавить фавиконку на сайт — поместить файл
favicon.ico в корень. Старый и железобетонный способ, который работает везде.Многие пользуются генераторами фавиконок. Потому что нужны файлы для разных сценариев и проще закинуть генератору исходник и получить готовый результат, чем делать всё руками.
Проблема генераторов в том, что они отдают архив с десятком фавиконок в разных форматах и размерах, а также полотно кода, который нужно вставить в
<head> для подключения. Это избыточно. Сегодня достаточно трёх файлов:-
/favicon.ico-
/icon.noscript-
/apple-touch-icon.pngЕсли сайт должен устанавливаться и работать как PWA, то к этому нужно добавить ещё четыре файла:
-
/manifest.webmanifest-
/icon-192.png-
/icon-mask.png-
/icon-512.pngВ статье от Злых Марсиан подробно объясняется, какие файлы использовать, как их подготовить и подключить к странице. Статья обновляется ежегодно, поэтому рекомендую периодически к ней возвращаться.
Не тащите в проекты гору устаревших фавиконок и не захламляйте
<head> лишними ссылками на эти файлы.#html
evilmartians.com
How to Favicon in 2025: Three files that fit most needs—Martian Chronicles, Evil Martians’ team blog
Prefer SVG over PNG, trust browsers to downscale, drop obscure formats—the ultimate, exhaustive guide to favicons for modern web. Includes steps for static HTML and Webpack.
❤21👍11
Предположения по производительности
Недавно общался с двумя разными разработчиками на тему производительности. Оба работали над улучшением производительности в рамках своих рабочих проектов и оказались в ситуации, когда предпринятые меры не дали значимого результата на цифрах.
То есть разработчики применили ряд распространённых оптимизаций, описанных в руководствах по улучшению производительности, и практически не получили прироста показателей в Pagespeed. Это натолкнуло меня на некоторые мысли.
Одна из проблем — неверные предположения. Разработчики запускают аудит, видят плохие показатели, смотрят на список проблем и выборочно их исправляют. Важно приоритизировать проблемы и делать упор на те, которые оказывают наибольшее влияние.
Нет смысла конвертировать шрифты и изображения в современные форматы, добавлять ленивую загрузку и проставлять атрибуты
Как и нет смысла всё это делать, если приложение загружает несколько мегабайт JS и рисуется на клиенте. В первую очередь нужно смотреть в сторону уменьшения размера бандла, разделения на чанки, удаления лишних зависимостей и оптимизацию доставки. А потом уже смотреть на другие проблемы.
Вторая мысль — оптимизации условно можно разделить на простые и сложные. Простые описаны во многих руководствах, легко гуглятся и просты в реализации. Но часто они направлены на исправление какой-то конкретной маленькой проблемы и не сильно влияют на общую картину.
Сложные оптимизации менее распространены, требуют комплексной работы и затрагивают архитектуру проекта. На это обычно нет времени, так как требуется достаточно длительный рефакторинг. Но именно такие оптимизации дают ощутимые результаты.
Ещё оптимизации могут стрелять в ноги.
Улучшения в одном месте могут привести к ухудшениям в другом. Перед началом работ по улучшению производительности стоит делать контрольные замеры, вносить точечные изменения и делать повторные замеры для сравнения. Для итераций можно использовать Lighthouse в DevTools не смотря на то, что он не показывает реальную картину.
#performance
Недавно общался с двумя разными разработчиками на тему производительности. Оба работали над улучшением производительности в рамках своих рабочих проектов и оказались в ситуации, когда предпринятые меры не дали значимого результата на цифрах.
То есть разработчики применили ряд распространённых оптимизаций, описанных в руководствах по улучшению производительности, и практически не получили прироста показателей в Pagespeed. Это натолкнуло меня на некоторые мысли.
Одна из проблем — неверные предположения. Разработчики запускают аудит, видят плохие показатели, смотрят на список проблем и выборочно их исправляют. Важно приоритизировать проблемы и делать упор на те, которые оказывают наибольшее влияние.
Нет смысла конвертировать шрифты и изображения в современные форматы, добавлять ленивую загрузку и проставлять атрибуты
width и height, если время получения первого байта (TTFB) составляет 1.5 секунды. В первую очередь нужно разбираться с сервером или с сетью.Как и нет смысла всё это делать, если приложение загружает несколько мегабайт JS и рисуется на клиенте. В первую очередь нужно смотреть в сторону уменьшения размера бандла, разделения на чанки, удаления лишних зависимостей и оптимизацию доставки. А потом уже смотреть на другие проблемы.
Вторая мысль — оптимизации условно можно разделить на простые и сложные. Простые описаны во многих руководствах, легко гуглятся и просты в реализации. Но часто они направлены на исправление какой-то конкретной маленькой проблемы и не сильно влияют на общую картину.
Сложные оптимизации менее распространены, требуют комплексной работы и затрагивают архитектуру проекта. На это обычно нет времени, так как требуется достаточно длительный рефакторинг. Но именно такие оптимизации дают ощутимые результаты.
Ещё оптимизации могут стрелять в ноги.
preload ускоряет загрузку критического ресурса, но откладывает другие. Ленивая загрузка полезна, но не в начальной области просмотра. CDN сокращает расстояние до пользователя, но добавляет соединение к стороннему домену.Улучшения в одном месте могут привести к ухудшениям в другом. Перед началом работ по улучшению производительности стоит делать контрольные замеры, вносить точечные изменения и делать повторные замеры для сравнения. Для итераций можно использовать Lighthouse в DevTools не смотря на то, что он не показывает реальную картину.
#performance
👍11🔥2❤1
Разметка бокового фильтра: итоги
Не так давно я делал опрос, какой элемент использовать для разметки области с фильтром в интернет-магазине.
Самым популярным выбором, предсказуемо, стал
Вариант
Если рассматривать фильтр как способ навигации по каталогу, может подойти
Фильтр обычно состоит из групп флажков, радио-кнопок, ползунков и полей ввода для цен. Мне подсознательно хочется использовать для этого
Сам по себе элемент
Есть элемент
Я пришёл к двум решениям. Первое — совместить форму с семантикой
Одним из этих двух способов я бы разметил фильтр в интернет-магазине. Причём не важно, находится он сбоку, сверху или где-то ещё. Склоняюсь к первому варианту, так как нет лишнего элемента и форма совмещает свои функции с ориентиром
#html #a11y
Не так давно я делал опрос, какой элемент использовать для разметки области с фильтром в интернет-магазине.
Самым популярным выбором, предсказуемо, стал
<aside>. Он закрепился в массовом сознании как элемент для боковых колонок. Фильтр в интернет-магазинах чаще всего отображён в виде боковой панели, поэтому <aside>. Семантика элемента, в принципе, подходит для фильтра, но об этом в отдельном посте.Вариант
<div role="group"> я бы исключил. Во-первых, есть встроенные элементы <fieldset> и <legend>, которые создают именованную группу для набора полей. Во-вторых — это группировка без семантической нагрузки и ориентира. На мой взгляд фильтр достаточно важен и его стоит выделить в ориентир.<section> тоже выглядит сомнительно. Он подходит для разметки разделов, для которых нет более подходящих семантических ориентиров. Это подойдёт для структуризации страницы с большим количеством разделов. Для фильтра есть более подходящие варианты.Если рассматривать фильтр как способ навигации по каталогу, может подойти
<nav>. Но в классическом понимании навигация — это набор ссылок на другие страницы, а не набор элементов управления. Поэтому <nav> я бы тоже исключил из списка вариантов.Фильтр обычно состоит из групп флажков, радио-кнопок, ползунков и полей ввода для цен. Мне подсознательно хочется использовать для этого
<form>. Плюсом Form API и прогрессивное улучшение от классической отправки формы с перезагрузкой до AJAX.Сам по себе элемент
<form> не ориентир, пока у него нет имени. Это легко исправляется атрибутами aria-labelledby или aria-label. Формы, как мне кажется, уже достаточно и оборачивать фильтр чем-то ещё будет избыточно.Есть элемент
<search>, который по описанию прямо предназначен для разметки поиска или фильтрации. Кажется, на нём и нужно остановить выбор. Но если фильтр уже размечен через <form> с именем?Я пришёл к двум решениям. Первое — совместить форму с семантикой
<search>. У элемента <form> согласно спецификации ARIA in HTML можно указывать роль search. Второе — не добавлять форме имя и не превращать её в ориентир, а обернуть элементом <search>.<!-- 1 -->
<form
action="/catalog"
method="get"
autocomplete="off"
novalidate
role="search"
aria-label="Фильтр"
>
<!-- элементы фильтра -->
</form>
<!-- 2 -->
<search aria-label="Фильтр">
<form
action="/catalog"
method="get"
autocomplete="off"
novalidate
>
<!-- элементы фильтра -->
</form>
</search>
Одним из этих двух способов я бы разметил фильтр в интернет-магазине. Причём не важно, находится он сбоку, сверху или где-то ещё. Склоняюсь к первому варианту, так как нет лишнего элемента и форма совмещает свои функции с ориентиром
search.#html #a11y
❤15👍8
ARIA Notify
Члены команды разработки Edge анонсировали новую функцию под названием ARIA Notify. Это новый API для вызова оповещений для целей доступности. API пока доступен за origin trial или экспериментальным флагом в Edge 136.
В стандарте ARIA есть концепция «живых регионов» (live regions). Это некоторые области на странице, изменения контента в которых приводят к озвучке этих изменений программами чтения с экрана. Таня Фокина написала подробную статью про «живые регионы» в Доке.
Кратко лишь скажу, что с технической точки зрения это набор ролей, свойств и встроенных HTML-элементов с некоторыми из этих возможностей для оповещения пользователей вспомогательных технологий о каких-либо асинхронных изменениях на странице.
Это применяется для:
- динамически изменяющихся данных (изменение цены в зависимости от выбранных опций, количество товаров в корзине, новые сообщения в чате);
- ошибок (неверные данные в форме, ошибка производимой операции);
- уведомлений (новые письма, изменение статуса заявки, всплывающие «тосты»);
- информирования о событиях (переключение слайда в галерее, окончание загрузки).
Работа с «живыми регионами» достаточно сложная. Нужно разобраться в многообразии ролей и состояний для выбора нужной комбинации. Затем проверить интерпретацию в разных программах чтения с экрана. После написать механизм внедрения «живых регионов» на страницу таким образом, чтобы это срабатывало.
Вместо этого хотелось бы вызвать какой-то простой метод браузера, передать ему текст, который скринридеру нужно озвучить, и важность озвучки. Команда Edge как раз такой метод реализовала в рамках более раннего предложения.
Метод
Посмотрим, чем закончится этот эксперимент и что изменится. Вероятно, ARIA Notify заедет в виде стабильного API в одном из ближайших релизов Edge. А так как это Chromium, вслед за Edge функция может появиться в Chrome и других браузерах на этом движке.
#web_api #a11y
Члены команды разработки Edge анонсировали новую функцию под названием ARIA Notify. Это новый API для вызова оповещений для целей доступности. API пока доступен за origin trial или экспериментальным флагом в Edge 136.
В стандарте ARIA есть концепция «живых регионов» (live regions). Это некоторые области на странице, изменения контента в которых приводят к озвучке этих изменений программами чтения с экрана. Таня Фокина написала подробную статью про «живые регионы» в Доке.
Кратко лишь скажу, что с технической точки зрения это набор ролей, свойств и встроенных HTML-элементов с некоторыми из этих возможностей для оповещения пользователей вспомогательных технологий о каких-либо асинхронных изменениях на странице.
Это применяется для:
- динамически изменяющихся данных (изменение цены в зависимости от выбранных опций, количество товаров в корзине, новые сообщения в чате);
- ошибок (неверные данные в форме, ошибка производимой операции);
- уведомлений (новые письма, изменение статуса заявки, всплывающие «тосты»);
- информирования о событиях (переключение слайда в галерее, окончание загрузки).
Работа с «живыми регионами» достаточно сложная. Нужно разобраться в многообразии ролей и состояний для выбора нужной комбинации. Затем проверить интерпретацию в разных программах чтения с экрана. После написать механизм внедрения «живых регионов» на страницу таким образом, чтобы это срабатывало.
Вместо этого хотелось бы вызвать какой-то простой метод браузера, передать ему текст, который скринридеру нужно озвучить, и важность озвучки. Команда Edge как раз такой метод реализовала в рамках более раннего предложения.
// Вызов оповещения в контексте документа
document.ariaNotify(
'Иван Иванов присоединился к звонку'
);
// Вызов оповещения в контексте конкретного элемента
document
.querySelector('#text-editor')
.ariaNotify(
'Выделен полужирный текст'
);
// Вызов оповещения с обычным приоритетом
document.ariaNotify(
'Настройки профиля обновлены',
{ priority: 'normal' }
);
// Вызов оповещения с высоким приоритетом
document.ariaNotify(
'Данные не сохранены',
{ priority: 'high' }
);
Метод
ariaNotify() вызывается у document или конкретного элемента и генерирует сообщение, как если бы в документ был вставлен «живой регион» или контент существующего был обновлён. Второй аргумент опциональный, принимает объект с единственным пока-что параметром priority.priority: 'normal' генерирует обычное сообщение. Оно озвучивается после того, как программа чтения с экрана закончит начатую ранее озвучку. С 'high' программа приостановит начатую озвучку и немедленно озвучит сообщение. Похоже, это соответствует механике атрибута aria-live="polite" и aria-live="assertive".Посмотрим, чем закончится этот эксперимент и что изменится. Вероятно, ARIA Notify заедет в виде стабильного API в одном из ближайших релизов Edge. А так как это Chromium, вслед за Edge функция может появиться в Chrome и других браузерах на этом движке.
#web_api #a11y
Microsoft Edge Blog
Creating a more accessible web with Aria Notify
We're excited to announce the availability, as a developer and origin trial, of ARIA Notify, a new API that's designed to make web content
😇8❤2👍2🔥1
CSS reading-flow
Вслед за анонсом от Edge, Рейчел Эндрю из команды Chrome поделилась новой функцией для улучшения доступности. Она будет доступна с выходом Chrome 137.
Flexbox и grid позволяют гибко располагать элементы на экране и реализовывать практически любые задумки дизайнеров. Иногда эти задумки выглядят так, что порядок элементов меняется в зависимости от размеров экрана.
Элементы flex-контейнера можно разворачивать значениями
В grid-контейнере возможностей больше. Порядок элементов задаётся по номерам или именам grid-линий, именованными областями или как решит браузер (
Эти возможности меняют только визуальный порядок, но не порядок в DOM, что приводит к проблемам с доступностью. Новые CSS-свойства
Без
Есть значения
#css #a11y
Вслед за анонсом от Edge, Рейчел Эндрю из команды Chrome поделилась новой функцией для улучшения доступности. Она будет доступна с выходом Chrome 137.
Flexbox и grid позволяют гибко располагать элементы на экране и реализовывать практически любые задумки дизайнеров. Иногда эти задумки выглядят так, что порядок элементов меняется в зависимости от размеров экрана.
Элементы flex-контейнера можно разворачивать значениями
row-reverse и column-reverse свойства flex-direction. Порядок конкретных элементов можно менять через свойство order.В grid-контейнере возможностей больше. Порядок элементов задаётся по номерам или именам grid-линий, именованными областями или как решит браузер (
grid-auto-flow).Эти возможности меняют только визуальный порядок, но не порядок в DOM, что приводит к проблемам с доступностью. Новые CSS-свойства
reading-flow и reading-order должны решить эти проблемы.reading-flow управляет порядком элементов flex и grid-контейнеров, который передаётся дереву доступности. Можно включить соответствие визуальному порядку элементов, а не их порядку в DOM.reading-order позволяет переопределить порядок конкретного элемента для дерева доступности, подобно тому, как order меняет положение конкретного элемента внутри flex-контейнера.<style>
.box {
display: flex;
flex-direction: row-reverse;
reading-flow: flex-visual;
}
.box :nth-child(1) {
order: 2;
}
</style>
<div class="box">
<a href="#">1</a>
<a href="#">2</a>
<a href="#">3</a>
</div>
<!--
Визуальный порядок:
1 3 2
-->
Без
reading-flow порядок фокусировки ссылок был бы как в DOM: 1, 2, 3. Это не соответствует тому, что отображается на экране. Значение flex-visual передаёт порядок в соответствии с визуальным расположением элементов: 1, 3, 2.flex-flow передаёт дереву доступности порядок, соответствующий текущему расположению элементов согласно потоку flex-контейнера с учётом row-reverse: 2, 3, 1.Есть значения
grid-rows и grid-columns для передачи порядка по строкам или по столбцами для grid-контейнеров. На специальной странице предлагаются разные примеры использования новых свойств. Там же есть ссылки, где можно оставить обратную связь.#css #a11y
Chrome for Developers
Use CSS reading-flow for logical sequential focus navigation | Blog | Chrome for Developers
Learn how to use the new reading-flow and reading-order properties in Chrome 137.
🔥8👍7❤3🤔3🤓3
Загрузка скрытых изображений
Представьте задачу: нужно показывать разные изображения в зависимости от ширины области просмотра. Это может быть баннер в верхней части страницы с широким изображением для компьютеров и узким для телефонов. Иногда эту задачу решают двумя
Классы
По умолчанию изображения с
Поэтому правильнее будет использовать элементы
Также не стоит добавлять изображениям в верхней части страницы атрибут
#html #performance
Представьте задачу: нужно показывать разные изображения в зависимости от ширины области просмотра. Это может быть баннер в верхней части страницы с широким изображением для компьютеров и узким для телефонов. Иногда эту задачу решают двумя
<img> и служебными классами, которые управляют отображением.<div class="banner">
<img
src="banner-desktop.webp"
alt=""
width="1200"
height="600"
class="mobile-hide"
>
<img
src="banner-mobile.webp"
alt=""
width="400"
height="200"
class="desktop-hide"
>
<!-- пустой alt, декоративные изображения -->
</div>
Классы
mobile-hide и desktop-hide скрывают изображения на мобильных и десктопных экранах. Сами классы могут называться иначе, но суть в том, чтобы скрывать элемент на определённых размерах экрана.@media (width <= 599px) {
.mobile-hide {
display: none;
}
}
@media (width > 600px) {
.desktop-hide {
display: none;
}
}По умолчанию изображения с
display: none не загружаются. Но если изображение находится в верхней части страницы, которая видна при начальной загрузке, то вопреки display: none оно всё равно будет загружаться. Chrome, например, загружает 6 первых изображений, игнорируя свойство display.Поэтому правильнее будет использовать элементы
<picture> и <source> в сочетании с атрибутом media для выбора источника изображения в зависимости от медиа-запроса.<picture class="banner">
<source
src="banner-desktop.webp"
media="(width > 600px)"
width="1200"
height="600"
>
<img
src="banner-mobile.webp"
alt=""
width="400"
height="200"
>
</picture>
Также не стоит добавлять изображениям в верхней части страницы атрибут
loading="lazy". Ещё можно поэкспериментировать с приоритетом. А ещё <picture> можно использовать как контейнер и задавать ему любые свойства, чтобы не оборачивать в лишний <div>.#html #performance
🔥26👍4👎2❤1
Группировка классов
Глобальный атрибут
Согласно спецификации, в
Поэтому в
Энди Бэлл, автор CSS-методологии CUBE, предлагает использовать квадратные скобки
Эту идею можно позаимствовать и использовать вне CUBE. Также для улучшения читаемости можно использовать переносы строк в атрибутах. Можно даже придумать условные обозначения для разных групп классов и использовать в разделителях групп. На этапе сборки всё лишнее можно удалять.
#css
Глобальный атрибут
class позволяет хранить набор строковых ключей, которые затем можно использовать в селекторах CSS для применения стилей или в JS для поиска элементов.Согласно спецификации, в
class можно указывать произвольные токены, разделённые пробелами. Как таковых, ограничений какими должны быть токены нет. Единственное — синтаксис HTML, где кавычка считается концом значения атрибута.Поэтому в
class можно указывать любые символы. Методология БЭМ использует договорённость по именованию токенов с использованием двойных подчёркиваний и тире __ и --. Tailwind отрывается по полной и использует разные символы как часть собственного специального синтаксиса. Кто-то использует эмодзи в качестве токенов.Энди Бэлл, автор CSS-методологии CUBE, предлагает использовать квадратные скобки
[ ] или вертикальную черту | для группировки классов. Идея в том, чтобы разделить разные классы на группы и записать их в нужном порядке, разделив группы для лучшей читаемости.<article
class="[ card ] [ section box ] [ bg-base color-primary ]"
data-state="reversed"
></article>
<article
class="card | section box | bg-base color-primary"
data-state="reversed"
></article>
Эту идею можно позаимствовать и использовать вне CUBE. Также для улучшения читаемости можно использовать переносы строк в атрибутах. Можно даже придумать условные обозначения для разных групп классов и использовать в разделителях групп. На этапе сборки всё лишнее можно удалять.
<article
class="
@[ card ]
#[ section box ]
$[ bg-base color-primary ]
"
></article>
#css
🤔16👎14😐5💊4🔥3❤1
14th Global Accessibility Awareness Day
Сегодня, 15 мая, 14й Всемирный День Информирования о Доступности. Цель этой инициативы — больше говорить, думать и узнавать о цифровой доступности и людях с различными нарушениями.
В прошлом году я предлагал посмотреть два видео от WAI и Be My Eyes. Если не видели, хороший повод посмотреть. В этом году рекомендую посты про руководство по созданию доступного контента и обновлённый раздел «как люди с ограничеными возможностями пользуются Интернетом».
По хештегу #a11y@alexnozer_dev можно посмотреть последние публикации канала, затрагивающие тему доступности. Если вы собираетесь внедрять доступность в проект и у вас есть вопросы — вступайте в чат нашего сообщества по доступности. Там можно задать любые вопросы по цифровой и не только доступности.
#a11y
Сегодня, 15 мая, 14й Всемирный День Информирования о Доступности. Цель этой инициативы — больше говорить, думать и узнавать о цифровой доступности и людях с различными нарушениями.
В прошлом году я предлагал посмотреть два видео от WAI и Be My Eyes. Если не видели, хороший повод посмотреть. В этом году рекомендую посты про руководство по созданию доступного контента и обновлённый раздел «как люди с ограничеными возможностями пользуются Интернетом».
По хештегу #a11y@alexnozer_dev можно посмотреть последние публикации канала, затрагивающие тему доступности. Если вы собираетесь внедрять доступность в проект и у вас есть вопросы — вступайте в чат нашего сообщества по доступности. Там можно задать любые вопросы по цифровой и не только доступности.
#a11y
GAAD
Thursday, May 15, 2025, help us celebrate the 14th Global Accessibility Awareness Day (GAAD)! The purpose of GAAD is to get everyone talking, thinking and learning about digital access and inclusion, and the more than One Billion people with disabilities/impairments.
❤9👍3🔥3
flex-wrap: balance
Уна Кравец у себя в социальных сетях поделилась анонсом свойства
Свойство
У
В целом это небольшое, но приятное улучшение для flexbox. И, что важно, улучшение прогрессивное. Если браузер не поддерживает
#css
Уна Кравец у себя в социальных сетях поделилась анонсом свойства
flex-wrap: balance, которое уже доступно в Chrome Canary. Название и механика работы похожа на свойство text-wrap: balance, которое год назад появилось во всех браузерах. Оно меняет алгоритм переноса текста так, чтобы строки были примерно одинаковой длины или сбалансированными, откуда и название.text-wrap: balance решает проблему подвисших слов в заголовках, когда в первой строке много текста, а во второй одно или пара слов. Идея сделать такое же свойство для flexbox обсуждается с 2018 года. Сейчас элементы flex-контейнера переносятся по одному, если им не хватает места. Они ведут себя, по сути, как слова в обычных блоках с текстом.Свойство
flex-wrap: balance разрешает перенос элементов (по умолчанию flex-wrap: nowrap не разрешает), и включает алгоритм балансировки (в отличие от flex-wrap: wrap). На новую строку будет переноситься не только тот элемент, которому не хватило места в строке, а такое количество элементов, при котором общая ширина каждой строки будет примерно одинаковой.У
text-wrap: balance есть ограничение: балансировка действует для текста, у которого не более 6 строк в Chrome и не более 10 строк в Firefox. Ограничение действует из-за особенностей переноса текста и алгоритма балансировки. При большом количестве строк это может негативно сказываться на производительности. Будут ли подобные ограничения у flex-wrap: balance — не известно.В целом это небольшое, но приятное улучшение для flexbox. И, что важно, улучшение прогрессивное. Если браузер не поддерживает
flex-wrap: balance, страница не развалится. Главное дополнительно указать flex-wrap: wrap, чтобы браузер откатился к стандартному механизму переноса.#css
Bluesky Social
Una Kravets (@una.im)
Introducing 🤯 flex-wrap: balance 🤯
Would you use this?
⚠️ Not a real feature yet, just something one of our engineers has been working on.
(You can try it out in the latest Chrome Canary with the experimental web platform features flag though!)
Would you use this?
⚠️ Not a real feature yet, just something one of our engineers has been working on.
(You can try it out in the latest Chrome Canary with the experimental web platform features flag though!)
👍15🔥6❤2😍2
margin-trim
В спецификации CSS Box Model Module Level 4 есть интересное свойство
Допустим, есть список, между элементами которого нужны отступы. Довольно частая задача. Первым делом на ум приходит свойство
Отступ будет у всех элементов списка, хотя у последнего он не нужен. Можно сделать список flex или grid-контейнером и использовать свойство
Но превращать элемент в flex или grid-контейнер только ради отступов — это как забивать маленький тонкий гвоздь кувалдой. Вроде можно, но избыточно. А всё потому что у последнего элемента торчит ненужный отступ. Хотелось бы обойтись обычным
Не очень красиво, но работает. С
В примере обрезаются отступы дочерних элементов, которые примыкают к концу блочной оси контейнера. Иначе говоря, нижний отступ последнего элемента списка будет обрезан.
Браузерная поддержка
#css
В спецификации CSS Box Model Module Level 4 есть интересное свойство
margin-trim. Я когда-то слышал о нём, но не придавал особого значения. Возможно, потому что оно сейчас поддерживается только в Safari 16.4+. Недавно наткнулся на короткую заметку Криса Койера и решил разобраться.Допустим, есть список, между элементами которого нужны отступы. Довольно частая задача. Первым делом на ум приходит свойство
margin, в частности margin-bottom.li {
margin-bottom: 1rem;
}Отступ будет у всех элементов списка, хотя у последнего он не нужен. Можно сделать список flex или grid-контейнером и использовать свойство
gap для отступов между элементами. Это хорошее решение, которое многие рекомендуют и которое я сам использую. Но превращать элемент в flex или grid-контейнер только ради отступов — это как забивать маленький тонкий гвоздь кувалдой. Вроде можно, но избыточно. А всё потому что у последнего элемента торчит ненужный отступ. Хотелось бы обойтись обычным
margin. Для этого есть несколько решений./* 1. отступ вниз, убрать у последнего элемента */
li {
margin-bottom: 1rem;
}
li:last-child {
margin-bottom: 0;
}
/* 2. отступ вверх, убрать у первого элемента */
li {
margin-top: 1rem;
}
li:first-child {
margin-bottom: 0;
}
/* 3. отступ вниз всем, кроме последнего элемента */
li:not(:last-child) {
margin-bottom: 1rem;
}
/* 4. отступ вверх всем, кроме первого элемента */
li:not(:first-child) {
margin-top: 1rem;
}
/* 5. отступ вверх только соседним элементам */
li + li {
margin-top: 1rem;
}
Не очень красиво, но работает. С
margin-trim можно обойтись без этого. Свойство обрезает отступы, которые находятся между дочерними элементами и краями контейнера. Принимает от одного до четырёх ключевые слов: none, block, inline, block-start, block-end, inline-start и inline-end. ul {
margin-trim: block-end;
}
li {
margin-bottom: 1rem;
}В примере обрезаются отступы дочерних элементов, которые примыкают к концу блочной оси контейнера. Иначе говоря, нижний отступ последнего элемента списка будет обрезан.
margin-trim принимает только логические значения, а значит могут возникнуть конфликты с свойствами направлений при работе с языками, где другое направление письма. В таких ситуациях лучше полностью перейти на логические свойства.Браузерная поддержка
margin-trim пока ограничена Safari. Свойство не выглядит каким-то сложным, поэтому его могут внедрить без особого шума. Как бы оно помогло строить сетки в эпоху перехода с таблиц/float на flexbox. Там приходилось применять всякие хаки с отрицательными отступами у контейнера. Ну а подробнее про margin-trim в блоге WebKit.#css
WebKit
Easier layout with margin-trim
If you write a lot of CSS, you are familiar with those moments when you aren’t quite sure how to accomplish what you want to accomplish.
❤18👍8🌚2🔥1
Ecosystem Performance
Ecosystem Performance (нумероним e18e) — это инициатива от сообщества разработчиков, которые ставят перед собой цель улучшить производительность экосистемы JS за счёт работы с пакетами.
Репозиторий npm — самое большое хранилище пакетов. В то же время там огромное количество устаревших и несовместимых пакетов, которые незримо попадают в
Сообщество e18e ищет в популярных проектах раздутые, старые, неподдерживаемые, медленные и ненужные зависимости. Затем они удаляются или заменяются на более современные и быстрые аналоги.
Другое направление деятельности — модернизация существующих зависимостей: оптимизация кода, замена устаревших подходов на современные возможности JS в браузере и Node, сокращение числа зависимостей.
Также разработчики из e11e занимаются разработкой микро-библиотек по философии UNIX: один пакет хорошо решает одну задачу. Получаются лёгкие библиотеки для решения конкретной задачи. Если ищите библиотеку, взгляните на проекты UnJS и Tinylibs.
E18e — классная инициатива, движимая идеей открытого исходного кода. Они уже достигли определённых результатов. Из недавнего генератор статических сайтов Eleventy стал на 11% быстрее и на 22% меньше благодаря e18e.
#performance
Ecosystem Performance (нумероним e18e) — это инициатива от сообщества разработчиков, которые ставят перед собой цель улучшить производительность экосистемы JS за счёт работы с пакетами.
Репозиторий npm — самое большое хранилище пакетов. В то же время там огромное количество устаревших и несовместимых пакетов, которые незримо попадают в
node_modules и клиентский код как транзитивные зависимости.Сообщество e18e ищет в популярных проектах раздутые, старые, неподдерживаемые, медленные и ненужные зависимости. Затем они удаляются или заменяются на более современные и быстрые аналоги.
Другое направление деятельности — модернизация существующих зависимостей: оптимизация кода, замена устаревших подходов на современные возможности JS в браузере и Node, сокращение числа зависимостей.
Также разработчики из e11e занимаются разработкой микро-библиотек по философии UNIX: один пакет хорошо решает одну задачу. Получаются лёгкие библиотеки для решения конкретной задачи. Если ищите библиотеку, взгляните на проекты UnJS и Tinylibs.
E18e — классная инициатива, движимая идеей открытого исходного кода. Они уже достигли определённых результатов. Из недавнего генератор статических сайтов Eleventy стал на 11% быстрее и на 22% меньше благодаря e18e.
#performance
e18e.dev
Ecosystem Performance
👍13❤2🌚2
Google I/O 2025: What's new in web UI
20-21 мая прошла ежегодная конференция Google I/O. Уна Кравец выступила с презентацией «что нового в мире Web UI» в рамках трека, посвящённого вебу. На примере трёх интерфейсных паттернов она рассказала о множестве новых функций:
- Popover
-
- Invoker commands
- Anchor positioning
- Customizable
-
-
-
- Typed
-
- Scroll-driven animations
-
- Interest commands
-
-
Первый паттерн — список выбора опций, он же
Наряду с popover был доработан похожий элемент —
Следующий паттерн — карусели, которые можно создавать через CSS. В основе лежит прокрутка с привязкой. Полоса прокрутки скрывается свойством
Доработанная функция attr() открывает возможности передачи данных из HTML-атрибутов в CSS-свойства с приведением их к нужному типу и резервным значением. Функция
Так как карусели работают на основе прокрутки, Scroll-driven animations отлично их дополняют. С ними можно реализовать различные эффекты при прокрутке слайдов. Отключать неактивные слайды в CSS можно свойством
Завершает презентацию паттерн hover card, когда при наведении на какой-то элемент всплывает карточка с дополнительным контентом. Новый атрибут
CSS-свойство
Количество новых функций для UI-разработки поражает, но и вызывает вопросы. Есть риск получить сырые функции со сломанной доступностью, непроработанными API и багами. Но об этом в одном из ближайших постов. Тем не менее, новинки выглядят круто и всё больше и больше паттернов закрывается встроенными возможностями HTML и CSS.
#html #css #ui
20-21 мая прошла ежегодная конференция Google I/O. Уна Кравец выступила с презентацией «что нового в мире Web UI» в рамках трека, посвящённого вебу. На примере трёх интерфейсных паттернов она рассказала о множестве новых функций:
- Popover
-
closedby- Invoker commands
- Anchor positioning
- Customizable
<select>-
scrollbar-width-
::scroll-button-
::scroll-marker- Typed
attr()-
scroll-state()- Scroll-driven animations
-
popover=hint- Interest commands
-
scroll-snap-align-
scroll-snap-typeПервый паттерн — список выбора опций, он же
<select>. Теперь его можно стилизовать. Выпадающий список опций реализован как popover — отображаемый в верхнем слое элемент, переключаемый связанной с ним кнопкой. Для позиционирования выпадающего списка относительно кнопки используется Anchor positioning.Наряду с popover был доработан похожий элемент —
<dialog>. Атрибут closedby определяет способ закрытия, в том числе добавляет закрытие при нажатии вне диалога. Благодаря Invoker Commands открывать и закрывать диалог в модальном и немодальном режимах можно декларативно с помощью кнопок.Следующий паттерн — карусели, которые можно создавать через CSS. В основе лежит прокрутка с привязкой. Полоса прокрутки скрывается свойством
scrollbar-width: none. Псевдо-элемент ::scroll-button() добавляет кнопки «вперёд»/«назад», свойство scroll-marker-group добавляет контейнер для маркеров, который стилизуется через ::scroll-marker-group, а сами маркеры добавляются через ::scroll-marker.Доработанная функция attr() открывает возможности передачи данных из HTML-атрибутов в CSS-свойства с приведением их к нужному типу и резервным значением. Функция
scroll-state() используется в Container Queries и позволяет определить, зафиксирован ли sticky-элемент, находится ли элемент в точке привязки или есть ли возможность прокрутки.Так как карусели работают на основе прокрутки, Scroll-driven animations отлично их дополняют. С ними можно реализовать различные эффекты при прокрутке слайдов. Отключать неактивные слайды в CSS можно свойством
interactivity: inert, аналогом атрибута inert. Завершает презентацию паттерн hover card, когда при наведении на какой-то элемент всплывает карточка с дополнительным контентом. Новый атрибут
interesttarget работает по аналогии с popovertarget, но показывает связанный popover по наведению указателя, долгому тапу на тач-устройствах или фокусу вместо нажатия.CSS-свойство
interest-target-delay задаёт задержку перед отображением и скрытием. Псевдо-класс :has-interest работает как :hover, но учитывает задержку. Новое значение popover="hint" меняет поведение popover для более удобного создания всплывающих по наведению элементов.Количество новых функций для UI-разработки поражает, но и вызывает вопросы. Есть риск получить сырые функции со сломанной доступностью, непроработанными API и багами. Но об этом в одном из ближайших постов. Тем не менее, новинки выглядят круто и всё больше и больше паттернов закрывается встроенными возможностями HTML и CSS.
#html #css #ui
YouTube
What's new in web UI
Prepare to be dazzled by a symphony of fluidity, dynamism, and expressive power as we unveil the next generation of web UI. It’s a world where user experiences transcend the ordinary and developers become true visual orchestrators. Discover how you can turn…
🔥17❤2🤝2👍1
Google I/O 2025: Web animations today and tomorrow
Брамус на Google I/O выступил с презентацией про сегодняшние и будущие возможности веб-анимаций. Ненавязчивые и короткие анимации делают интерфейсы более отзывчивыми и приятными, поэтому их определённо стоит добавлять.
Директива
Ключевое слово
Свойство
Альтернативно анимировать размеры с ключевыми словами можно через функцию
Благодаря новому псевдо-элементу
Scroll-driven animations решают задачу анимации элементов с привязкой к прокрутке страницы. Они частично или полностью заменяют такие библиотеки, как AOS, SAL или даже GSAP.
View Transitions — это способ создавать анимированные переходы между обновлениями отображения в SPA или между загрузками страниц в MPA.
Анимации View Transitions можно настраивать в CSS с помощью псевдо-элементов и стандартного свойства
Для более удобной работы с группой элементов свойство
Свойство
Scoped View Transitions расширяет стандартные возможности и позволяет вызвать переходы не для всего документа, а для конкретного DOM-элемента. Это полезно для анимации сортировки или удаления элементов.
В видео-презентации Брамуса много ссылок на документацию и примеры, потому что на анимации нужно смотреть, словами их описать сложно. Очень много всего появилось и появится в недалёком будущем для создания анимаций, и это круто.
#css
Брамус на Google I/O выступил с презентацией про сегодняшние и будущие возможности веб-анимаций. Ненавязчивые и короткие анимации делают интерфейсы более отзывчивыми и приятными, поэтому их определённо стоит добавлять.
Директива
@starting-style задаёт стили, применяемые к элементу при первой отрисовке. Предназначена для анимации появления скрытых элементов, таких как диалоги, поповеры или выпадающие меню.Ключевое слово
allow-discrete используется в свойстве transition для анимации дискретных свойств. Это позволяет анимировать элементы, скрытые с помощью display: none, а для диалогов ещё анимировать фон (overlay).Свойство
intetpolate-size: allow-keywords делает возможным анимацию размерных свойств, которые принимают в качестве значений ключевые слова max-content, min-content, auto. Включить можно для всей страницы или конкретного селектора.Альтернативно анимировать размеры с ключевыми словами можно через функцию
calc-size(). Она принимает ключевые слова и переменную с размером элемента, а также позволяет производить математические операции.Благодаря новому псевдо-элементу
::details-content в сочетании с упомянутыми allow-discrete и interpolate-size: allow-keywords можно анимировать раскрытие и сворачивание контента <details> произвольной высоты.Scroll-driven animations решают задачу анимации элементов с привязкой к прокрутке страницы. Они частично или полностью заменяют такие библиотеки, как AOS, SAL или даже GSAP.
View Transitions — это способ создавать анимированные переходы между обновлениями отображения в SPA или между загрузками страниц в MPA.
Анимации View Transitions можно настраивать в CSS с помощью псевдо-элементов и стандартного свойства
animation. Альтернативно можно использовать Web Animations API в JS.Для более удобной работы с группой элементов свойство
view-transition-name расширено значением match-element, чтобы не присваивать уникальный идентификатор каждому элементу. Либо идентификатор можно получать из атрибута id с помощью обновлённой функции attr().Свойство
view-transition-group позволяет создавать переходы во вложенных элементах, где сейчас игнорируется overflow. Можно указать значение contains у контейнера или nearest у его элементов.Scoped View Transitions расширяет стандартные возможности и позволяет вызвать переходы не для всего документа, а для конкретного DOM-элемента. Это полезно для анимации сортировки или удаления элементов.
В видео-презентации Брамуса много ссылок на документацию и примеры, потому что на анимации нужно смотреть, словами их описать сложно. Очень много всего появилось и появится в недалёком будущем для создания анимаций, и это круто.
#css
YouTube
Web animations today and tomorrow
Join us to explore the latest advancements in web animation to help developers create richer, more dynamic, and performant web experiences. We'll cover new and upcoming features, including @starting-style, enhancements to View Transitions, the ability to…
🔥12❤2👍1
Webbed sites
Анонс Webbed sites от мастера сарказма, иронии и чёрно-белого видеопроизводства — Хейдона Пикеринга. Навеян недавним анонсом Figma sites с типичным набором проблем для такого рода инструментов, а также AI-генераторами.
От себя добавлю, что идея создания сайтов без технических навыков в визуальном редакторе или по текстовому описанию сама по себе не плохая. Но вот реализации в плане итогового результата откровенно плохи по моим меркам качества интерфейсов.
И зацените эту песню про divs в конце видео. Хоть вырезай и используй как гимн канала.
#html #a11y
Анонс Webbed sites от мастера сарказма, иронии и чёрно-белого видеопроизводства — Хейдона Пикеринга. Навеян недавним анонсом Figma sites с типичным набором проблем для такого рода инструментов, а также AI-генераторами.
От себя добавлю, что идея создания сайтов без технических навыков в визуальном редакторе или по текстовому описанию сама по себе не плохая. Но вот реализации в плане итогового результата откровенно плохи по моим меркам качества интерфейсов.
И зацените эту песню про divs в конце видео. Хоть вырезай и используй как гимн канала.
#html #a11y
briefs.video
Introducing: Webbed Sites
A video from Webbed Briefs
😁5🔥2🌚2❤1
You don't know HTML: нумерованные списки
В HTML есть элемент
Нумерованные списки используются не часто, но мест, где их можно применить, достаточно много. В дизайне встречаются блоки, где важен порядок элементов: рейтинг, хронология, многоэтапная форма, эпизоды подкаста и так далее.
Особенности списков могут помочь создавать такие блоки. Вместо того, чтобы генерировать номера в цикле при обработке серверных или клиентских шаблонов, позвольте браузеру сделать это за вас.
Атрибут
Атрибут
Атрибут
Атрибут
Маркер списка стилизуется при помощи псевдо-элемента
Такой вариант даёт полную свободу стилизации, но атрибуты
#ydkhtml
В HTML есть элемент
<ol>, который создаёт нумерованный или упорядоченный список. У таких списков есть встроенный счётчик и маркеры. По умолчанию они отображаются в виде цифр перед элементами списка.<ol>
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
</ol>
<!--
1. Foo
2. Bar
3. Baz
-->
Нумерованные списки используются не часто, но мест, где их можно применить, достаточно много. В дизайне встречаются блоки, где важен порядок элементов: рейтинг, хронология, многоэтапная форма, эпизоды подкаста и так далее.
Особенности списков могут помочь создавать такие блоки. Вместо того, чтобы генерировать номера в цикле при обработке серверных или клиентских шаблонов, позвольте браузеру сделать это за вас.
Атрибут
reversed меняет направление нумерации списка, от большего к меньшему. Сам порядок элементов при этом остаётся прежним. Удобно для списков «от последнего к первому».<ol reversed>
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
</ol>
<!--
3. Foo
2. Bar
1. Baz
-->
Атрибут
start задаёт начальное значение для отсчёта. Это позволяет разбивать большой список на несколько более мелких списков и продолжать нумерацию. Это применимо для вывода списка эпизодов подкаста с пагинацией. Атрибут start можно комбинировать с reversed и даже уйти в минус.<h2>Эпизоды</h2>
<ol start="12" reversed>
<li>Состояние доступности в 2024</li>
<li>Профессиональный рост в веб-доступности</li>
<li>ИИ, доступность и заменят ли нас машины</li>
</ol>
<!-- следующая страница -->
<h2>Эпизоды</h2>
<ol start="9" reversed>
<li>Визуальная и невизуальная доступность</li>
<li>Доступные тексты и текстовые альтернативы</li>
<li>Прошлое и настоящее WCAG</li>
</ol>
<!--
Эпизоды
12. Состояние доступности в 2024
11. Профессиональный рост в веб-доступности
10. ИИ, доступность и заменят ли нас машины
Эпизоды
9. Визуальная и невизуальная доступность
8. Доступные тексты и текстовые альтернативы
7. Прошлое и настоящее WCAG
-->
Атрибут
value задаёт значение счётчика текущему элементу списка. Общая нумерация продолжается с этого значения вверх или вниз в зависимости от наличия атрибута reversed. Это можно применить для пропуска значений при реализации блока с хронологией:<ol start="2015">
<li>Начало работы над проектом</li>
<li value="2017">Запуск первой версии продукта</li>
<li>Расширение команды разработчиков</li>
<li value="2020">Выход на международный рынок</li>
<li>Внедрение новых технологий</li>
<li>Получение престижной награды</li>
</ol>
<!--
2015. Начало работы над проектом
2017. Запуск первой версии продукта
2018. Расширение команды разработчиков
2020. Выход на международный рынок
2021. Внедрение новых технологий
2022. Получение престижной награды
-->
Атрибут
type задаёт один из предопределённых типов маркеров. Вместо арабских цифр можно использовать римские цифры или латинские буквы, причём как в верхнем регистре, так и в нижнем.<ol type="I">
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
</ol>
<ol type="a">
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
</ol>
<!--
I. Foo
II. Bar
III. Baz
a. Foo
b. Bar
c. Baz
-->
Маркер списка стилизуется при помощи псевдо-элемента
::marker, но доступен только ограниченный набор свойств. Можно сбросить стандартный счётчик и реализовать свой через свойство content псевдо-элемента ::before:ol {
list-style: none;
counter-reset: list;
}
li {
counter-increment: list;
}
li::before {
content: counter(list) '. ';
/* другие стили */
}Такой вариант даёт полную свободу стилизации, но атрибуты
start, reversed и value не будут работать. Частично их наличие можно учитывать при стилизации маркеров, используя селектор по атрибутам.#ydkhtml
❤23👍10🔥4🌚2
Стилизация счётчиков списка
Чтобы далеко не уходить от темы списков, предлагаю продолжение предыдущего поста, где расскажу про некоторые возможности стилизации маркеров.
Цифра в нумерованных списках — это псевдо-элемент
-
-
-
-
-
-
-
-
-
Интереснее всего свойство
Стандартный счётчик списка называется
При использовании стандартного счётчика таким образом будут работать атрибуты
Иногда нужно вывести цифры так, чтобы впереди были незначащие нули. Это делается с помощью передачи второго аргумента
Маркеры по умолчанию вынесены за пределы элементов списка. С помощью свойства
Если для маркеров нужна расширенная стилизация, можно перенести стандартный счётчик
#css
Чтобы далеко не уходить от темы списков, предлагаю продолжение предыдущего поста, где расскажу про некоторые возможности стилизации маркеров.
Цифра в нумерованных списках — это псевдо-элемент
::marker, в который браузер автоматически подставляет значение счётчика. Его можно базово стилизовать ограниченным набором свойств:-
font-*;-
white-space;-
color;-
text-combine-upright;-
unicode-bidi;-
direction;-
content;-
animation-*;-
transition-*.Интереснее всего свойство
content. Его можно переопределить, что сбросит стандартные маркеры со счётчиком:ol li::marker {
content: '🔹 ';
}
/*
🔹 Foo
🔹 Bar
🔹 Baz
*/
Стандартный счётчик списка называется
list-item. Используя функцию counter() для вывода значения счётчика в свойство content и встроенную конкатенацию строк, можно задать собственный суффикс. Это полезно, когда нужны скобки вместо стандартных точек:ol li::marker {
content: counter(list-item) ') ';
}
/*
1) Foo
2) Bar
3) Baz
*/
При использовании стандартного счётчика таким образом будут работать атрибуты
reversed и start. Атрибут value будет работать частично: значение установится, но отсчёт у следующего элемента будет от предыдущего значения счётчика. С помощью data-* атрибутов и attr() можно добавить возможность настройки префикса и суффикса в HTML для контент-менеджеров:ol {
--prefix: '';
--suffix: ') ';
}
ol li::marker {
content: var(--prefix) counter(list-item) var(--suffix);
}
ol[data-prefix] {
--prefix: attr(data-prefix);
}
ol[data-suffix] {
--suffix: attr(data-suffix);
}
/*
<ol data-prefix="[" data-suffix="] ">
...
</ol>
[1] Foo
[2] Bar
[3] Baz
*/
Иногда нужно вывести цифры так, чтобы впереди были незначащие нули. Это делается с помощью передачи второго аргумента
decimal-leading-zero в функцию counter():ol li::marker {
content: counter(list-item, decimal-leading-zero) '. ';
}
/*
09. Foo
10. Bar
11. Baz
*/
Маркеры по умолчанию вынесены за пределы элементов списка. С помощью свойства
list-style-position: inside можно поместить маркеры внутрь элементов списка, чтобы текст их обтекал:ol {
list-style-position: inside;
}
/*
1. Foo
Foo Foo
2. Bar
Bar Bar
3. Baz
Baz Baz
*/
Если для маркеров нужна расширенная стилизация, можно перенести стандартный счётчик
list-item в псевдо-элемент ::before. Все атрибуты списка продолжат работать, но псевдо-элемент ::before можно стилизовать без ограничений.ol {
list-style: none;
}
ol li::before {
content: counter(list-item) '. ';
/* другие стили */
}
#css
👍12🔥8❤3🆒2
counters() и counter-style
В начале недели я рассказал о нумерованных списках и предложил использовать их при реализации блоков с цифрами. Прошлый пост о том, как стилизовать счётчики. Завершаю неделю счётчиков рассказом о ещё двух возможностях: функции
Помимо функции
Первым аргументом
Директива
В
-
-
-
-
-
-
-
-
-
-
С помощью этих свойств можно определять счётчики для разных языков, письменностей и систем исчислений. На странице Ready-made Counter Styles от авторов спецификации собраны примеры реализации пользовательских счётчиков.
А вот пример счётчика от меня с использованием эмодзи-цифр:
Важный дисклеймер: маркеры списка зачитываются программами чтения с экрана. Поэтому взвесьте «за» и «против» в вашем конкретном случае. Если вы считаете маркеры избыточными, стоит вернуться к генерации цифр в шаблонах и скрыть их от программ чтения с экрана.
#css
В начале недели я рассказал о нумерованных списках и предложил использовать их при реализации блоков с цифрами. Прошлый пост о том, как стилизовать счётчики. Завершаю неделю счётчиков рассказом о ещё двух возможностях: функции
counters() и директиве @counter-style.Помимо функции
counter(), которая используется для вывода счётчиков, есть ещё одна похожая функция — counters(). Её задача — выводить вложенные счётчики, что применимо к многоуровневым спискам или к нумерованным заголовкам разделов и подразделов:ol {
counter-reset: section;
}
li {
counter-increment: section;
}
li::marker {
content: counters(section, '.') ' ';
}
/*
1 Foo
1.1 Bar
1.2 Baz
1.2.1 Foo
2 Bar
2.1 Baz
*/Первым аргументом
counters() принимает название счётчика, затем разделитель и опционально можно указать тип счётчика в качестве третьего аргумента.Директива
@counter-style позволяет определять собственные типы счётчиков по аналогии с тем, как @font-face определяет семейство шрифта или @property определяет пользовательское свойство.В
@counter-style предлагает следующие опции:-
system — система нумерации. Значения: cyclic, numeric, alphabetic, symbolic, additive и fixed. Можно наследоваться от существующих типов счётчиков;-
symbols — список символов, используемых для генерации маркеров;-
additive-symbols — список дополнительных символов, используемых при системе нумерации additive;-
negative — символ, который добавляется для отрицательных значений счётчика;-
prefix — префикс, добавляемый перед значением счётчика;-
suffix — суффикс, добавляемый после значения счётчика;-
range — диапазон значений счётчика, к которому применяются правила пользовательского счётчика;-
pad — символ, который добавляется перед значением счётчика для достижения одинакового количества символов всех значений счётчика;-
speak-as — определяет как озвучивать маркеры списка;-
fallback — тип счётчика, к которому нужно вернуться, если не удаётся сгенерировать значение в текущем типе.С помощью этих свойств можно определять счётчики для разных языков, письменностей и систем исчислений. На странице Ready-made Counter Styles от авторов спецификации собраны примеры реализации пользовательских счётчиков.
А вот пример счётчика от меня с использованием эмодзи-цифр:
@counter-style emoji-numbers {
system: numeric;
symbols: '0️⃣' '1️⃣' '2️⃣' '3️⃣' '4️⃣' '5️⃣' '6️⃣' '7️⃣' '8️⃣' '9️⃣';
suffix: ' ';
negative: '➖';
pad: 2 '0️⃣';
}
ol {
list-style: emoji-numbers;
}
/*
<ol start="-1">
...
</ol>
➖1️⃣ Foo
0️⃣0️⃣ Bar
0️⃣1️⃣ Baz
...
0️⃣9️⃣ Foo
1️⃣0️⃣ Bar
...
*/Важный дисклеймер: маркеры списка зачитываются программами чтения с экрана. Поэтому взвесьте «за» и «против» в вашем конкретном случае. Если вы считаете маркеры избыточными, стоит вернуться к генерации цифр в шаблонах и скрыть их от программ чтения с экрана.
#css
👍3🌚2❤1🔥1
Вкладки с помощью :target
В чате веб-стандартов не так давно обсуждали создание вкладок на основе ссылок, состояния в URL и псевдо-класса
Вкладки из ссылок и
Технически всё работает как обычное интерактивное содержание с якорными ссылками и несколькими разделами. Разница в том, что разделы скрыты и не совсем очевидно, что они появляются при переходе по ссылке. UX не очень, но интерфейсом можно воспользоваться. При грамотной реализации через
Но это не вкладки. Потому что вкладки — комплексный виджет с определёнными функциями и поведением. В веб они пришли из десктопа вместе с механикой работы и внешним видом. Для пользователей это привычный и понятный паттерн, встреча с которым формирует определённые ожидания. Вкладки будут вкладками только если соответствуют требованиям.
Роли
Добавление ролей к вкладкам из ссылок и
- фокусируются все вкладки, а не только активная;
- вкладки переключаются клавишами
- нет информации о том, выбрана вкладка или нет;
- при выборе вкладки фокус переносится на элемент панели вместо того, чтобы оставаться на вкладке;
- меняется текущий URL (фрагмент), что характерно для ссылок, но не вкладок;
- изменение URL сбрасывает состояние других вкладок на странице, чего происходить не должно.
Вывод такой: если вам нужны вкладки, не надо делать их с помощью
- <sl-tab-group>
- <tab-container>
- <generic-tabs>
Или подумайте, нужны ли вам вообще вкладки. Может быть, простого размещения контента друг за другом в естественном потоке будет достаточно. Сделать это ещё проще и быстрее, чем вкладки с помощью
#css #ux #a11y
В чате веб-стандартов не так давно обсуждали создание вкладок на основе ссылок, состояния в URL и псевдо-класса
:target. По итогу Артём Арутюнян написал об этом пост в своём канале. Для понимания механики работы предлагаю посмотреть доклад Ивана Бабкова. В комментариях к посту некоторые высказались против такой реализации по соображениям доступности. Это те самые CSS-хаки, о которых я не так давно писал.Вкладки из ссылок и
:target не такое уж плохое решение в условиях, когда нужно сделать быстро. Лучше так, чем <div>-ы с onclick и простым переключением классов. Ни то, ни другое нельзя назвать вкладками, но в первом случае получается решение без JS, с фокусируемыми семантическими ссылками на нужные части страницы. Технически всё работает как обычное интерактивное содержание с якорными ссылками и несколькими разделами. Разница в том, что разделы скрыты и не совсем очевидно, что они появляются при переходе по ссылке. UX не очень, но интерфейсом можно воспользоваться. При грамотной реализации через
hidden="until-found" даже поиск по странице будет работать.Но это не вкладки. Потому что вкладки — комплексный виджет с определёнными функциями и поведением. В веб они пришли из десктопа вместе с механикой работы и внешним видом. Для пользователей это привычный и понятный паттерн, встреча с которым формирует определённые ожидания. Вкладки будут вкладками только если соответствуют требованиям.
Роли
tablist, tab и tabpanel передают семантику. Добавление атрибута role — это обещание, что элемент работает определённым образом. Пользователи полагаются на это обещание и ожидают соответствующую структуру контента, вложенные элементы, клавиатурную навигацию и поведение. JS реагирует на события и меняет состояние.Добавление ролей к вкладкам из ссылок и
:target может показаться хорошей идеей для улучшения доступности. Но итоговый результат не выполняет обещание:- фокусируются все вкладки, а не только активная;
- вкладки переключаются клавишами
Tab/Shift+Tab вместо стрелок;- нет информации о том, выбрана вкладка или нет;
- при выборе вкладки фокус переносится на элемент панели вместо того, чтобы оставаться на вкладке;
- меняется текущий URL (фрагмент), что характерно для ссылок, но не вкладок;
- изменение URL сбрасывает состояние других вкладок на странице, чего происходить не должно.
Вывод такой: если вам нужны вкладки, не надо делать их с помощью
:target, радио-кнопок и прочих хаков. Правильная реализация использует ARIA и JS в соответствии с требованиями. Если нет времени разбираться и нужно быстрое решение — используйте готовые веб-компоненты, в которых кто-то уже позаботился о доступности. Вот мои рекомендации:- <sl-tab-group>
- <tab-container>
- <generic-tabs>
Или подумайте, нужны ли вам вообще вкладки. Может быть, простого размещения контента друг за другом в естественном потоке будет достаточно. Сделать это ещё проще и быстрее, чем вкладки с помощью
:target. И JS не понадобится, и думать о ролях, свойствах и обещаниях не придётся.#css #ux #a11y
100❤15🔥4👍1