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
Проблемы CSS-каруселей
Не так давно команда Chrome поделилась анонсом CSS-каруселей из спецификации CSS Overflow Module Level 5, а позже их показали на Google I/O 2025. Это крутая штука, но лично у меня возникли вопросы к реализации. И не только у меня.
Дэвид Бушелл выразил недовольство по поводу использования псевдо-элементов для создания интерактивных кнопок карусели (стрелок и маркеров). Я с ним согласен, это выглядит как-то противоестественно.
Псевдо-элементы ограничены свойством
CSS-карусели позиционируются как доступное решение, чтобы избежать проблем с библиотеками. На деле есть вопросы к доступности. Сара Суайдан протестировала текущую реализацию и написала об этом статью.
Контейнеру с маркерами добавляется роль
Роли
В общем актуальная на сегодня реализация откровенно сырая. Возможно, спешили к Google I/O. CSS-карусели в текущем виде выпустили в Chrome 135 и это плохо, потому что они нуждаются в доработках.
#css #a11y
Не так давно команда Chrome поделилась анонсом CSS-каруселей из спецификации CSS Overflow Module Level 5, а позже их показали на Google I/O 2025. Это крутая штука, но лично у меня возникли вопросы к реализации. И не только у меня.
Дэвид Бушелл выразил недовольство по поводу использования псевдо-элементов для создания интерактивных кнопок карусели (стрелок и маркеров). Я с ним согласен, это выглядит как-то противоестественно.
Псевдо-элементы ограничены свойством
content с простым текстом или изображением по сравнению с контентом в HTML. Я за композицию элементов, как <summary> вкладывается в <details> для кнопки переключения видимости.CSS-карусели позиционируются как доступное решение, чтобы избежать проблем с библиотеками. На деле есть вопросы к доступности. Сара Суайдан протестировала текущую реализацию и написала об этом статью.
Контейнеру с маркерами добавляется роль
tablist, а маркерам роль tab и навигация стрелками согласно паттерну вкладок и одной из реализаций паттерна карусели. Но слайды не получают роль tabpanel и не связываются с маркерами.Роли
tablist и tab добавляются без учёта элемента, из которого создана карусель. То же самое с кнопками переключения. При использовании списка <ul>, внутри появляются недопустимые элементы и ломают семантику.В общем актуальная на сегодня реализация откровенно сырая. Возможно, спешили к Google I/O. CSS-карусели в текущем виде выпустили в Chrome 135 и это плохо, потому что они нуждаются в доработках.
#css #a11y
😭16🔥5❤1
«Мощь современных технологий»
Блуждая по социальным сетям, я наткнулся на пост Алекса Рассела и не смог пройти мимо. Контекст: OpenAI поделилась лэндингом, на котором сообщила о приобретении и поглощении технологической компании io.
На лэндинге несколько абзацев текста, логотип, изображение и видео. Далее привожу адаптацию поста Алекса:
В одной из ведущих технологических компаний, с огромными ресурсами и доступом к лучшим разработчикам мира не смогли нормально сделать лэндинг с парой картинок и текстом.
Описание изображения:
Фрагмент модуля JavaScript, сгенерированного с помощью Webpack. Модуль содержит буфер из строки в шестнадцатеричном формате. По миникарте видно, что большая часть файла занята этой строкой, что заметно увеличивает его размер.
#performance
Блуждая по социальным сетям, я наткнулся на пост Алекса Рассела и не смог пройти мимо. Контекст: OpenAI поделилась лэндингом, на котором сообщила о приобретении и поглощении технологической компании io.
На лэндинге несколько абзацев текста, логотип, изображение и видео. Далее привожу адаптацию поста Алекса:
Узрите мощь полностью функциональной страницы на Next.js и Tailwind! 3мб (11.4мб без сжатия) JS на критическом пути рендеринга, чтобы отобразить 1.4кб (2.8кб без сжатия) текста, изображение и видео «ниже сгиба»:
https://www.webpagetest.org/video/compare.php?tests=250523_BiDc3Y_JJ0-r:1-c:0
Больше всего я хочу, чтобы инженеры перестали восторгаться что они использовали, а задавались вопросом «насколько это хорошо?».
«Почему основной поток заблокирован на несколько секунд перед отображением текста?» — спросите вы. Это чертовски хороший вопрос. Наряду с вопросами «как это вообще отправили в релиз?» и «почему Vercel не предложила помощь по ручной настройке, чтобы избежать дальнейшего позора?».
В этот список можно добавить вопросы «почему для hero-изображения в верхней части страницы установлено loading="lazy"?» и «как тут оказался рендерер markdown?» или «что делает JS-движок LaTeX на критическом пути?».
Вы также можете задаться вопросом, что это за чертовщина (на скриншоте), и, возможно, вам придётся разобраться. Это диапазоны IP-адресов стран в бинарном формате, размером 338кб (1.3мб без сжатия). И всё это на критическом пути рендеринга.
Эти и другие загадки ожидают в бандлах OpenAI, если заглянуть и изучить их. Воистину, вершина технологий в 2025 году!
В одной из ведущих технологических компаний, с огромными ресурсами и доступом к лучшим разработчикам мира не смогли нормально сделать лэндинг с парой картинок и текстом.
Описание изображения:
#performance
🤣15🫡7❤6😢4🤡4
Изображения против JS
Иногда встречается такое мнение:
Дело в том, что 500кб JS не равны 500кб изображения с точки зрения процесса обработки ресурсов браузером. Размер файлов одинаковый, но влияние на производительность разное.
Тяжёлые изображения не блокируют основной поток, отрисовку и HTML-парсер. Браузер продолжает разбирать документ, искать ресурсы и рисовать пиксели на экране, пока изображения загружаются.
Если изображения находятся ниже начальной области отображения, их можно загружать лениво. Браузер не будет их скачивать, пока они не окажутся в пределах области просмотра. JS тоже можно загружать лениво, но это более сложная задача.
После загрузки изображение нужно декодировать и ресайзить. Последнее не требуется, если исходные размеры соответствуют размерам блока. Декодирование происходит очень быстро, выполняется на видеокарте и не блокирует поток.
С JS происходит больше операций. После загрузки его нужно разобрать и проверить синтаксис. Далее код нужно скомпилировать в набор низкоуровневых инструкций для дальнейшего выполнения. Эти операции требуют времени.
Так как в JS можно вызвать редирект на другую страницу, дописать в поток парсера новую разметку, обращаться к узлам DOM и модифицировать их, браузер приостанавливает отрисовку и парсер, пока обрабатывает JS.
Общее время блокировки основного потока при выполнении JS известно как Total Blocking Time, а задачи длительностью более 50мс известны как Long Tasks. Оба явления приводят к подтормаживанию интерфейса и ухудшают отзывчивость.
При выполнении JS может возникнуть ошибка. Если HTML и CSS толерантны к ошибкам и продолжают работать, то ошибки в JS приводят к полной остановке дальнейшего выполнения.
Из-за ошибок в JS интерфейс может утратить функциональность. В случае SPA пользователи увидят белый экран. При ошибке во время загрузки изображения функциональность не утратится, а вместо изображения отобразится alt-текст, который можно стилизовать.
Не смотря на одинаковый размер исходных файлов изображения и JS, у последнего больше влияния на загрузку страницы, больше точек отказа и хуже последствия при возникновении ошибки.
#performance #js
Иногда встречается такое мнение:
Подумаешь, 500кб JS. Это ерунда в современном мире. Одна картинка весит столько же, а на странице несколько таких картинок.
Дело в том, что 500кб JS не равны 500кб изображения с точки зрения процесса обработки ресурсов браузером. Размер файлов одинаковый, но влияние на производительность разное.
Тяжёлые изображения не блокируют основной поток, отрисовку и HTML-парсер. Браузер продолжает разбирать документ, искать ресурсы и рисовать пиксели на экране, пока изображения загружаются.
Если изображения находятся ниже начальной области отображения, их можно загружать лениво. Браузер не будет их скачивать, пока они не окажутся в пределах области просмотра. JS тоже можно загружать лениво, но это более сложная задача.
После загрузки изображение нужно декодировать и ресайзить. Последнее не требуется, если исходные размеры соответствуют размерам блока. Декодирование происходит очень быстро, выполняется на видеокарте и не блокирует поток.
С JS происходит больше операций. После загрузки его нужно разобрать и проверить синтаксис. Далее код нужно скомпилировать в набор низкоуровневых инструкций для дальнейшего выполнения. Эти операции требуют времени.
Так как в JS можно вызвать редирект на другую страницу, дописать в поток парсера новую разметку, обращаться к узлам DOM и модифицировать их, браузер приостанавливает отрисовку и парсер, пока обрабатывает JS.
Общее время блокировки основного потока при выполнении JS известно как Total Blocking Time, а задачи длительностью более 50мс известны как Long Tasks. Оба явления приводят к подтормаживанию интерфейса и ухудшают отзывчивость.
При выполнении JS может возникнуть ошибка. Если HTML и CSS толерантны к ошибкам и продолжают работать, то ошибки в JS приводят к полной остановке дальнейшего выполнения.
Из-за ошибок в JS интерфейс может утратить функциональность. В случае SPA пользователи увидят белый экран. При ошибке во время загрузки изображения функциональность не утратится, а вместо изображения отобразится alt-текст, который можно стилизовать.
Не смотря на одинаковый размер исходных файлов изображения и JS, у последнего больше влияния на загрузку страницы, больше точек отказа и хуже последствия при возникновении ошибки.
#performance #js
👍20🔥6❤2💯1
Импорт (почти) чего угодно в браузере
Стандарт ES2015 (ES6) принёс в JS систему модулей — ESM. Те самые
- Путь к модулю должен быть относительным (начинаться с
- Путь к модулю должен заканчиваться именем файла с расширением
- Импортировать можно только JS-модули.
ESM не стоит на месте. Недавно в стандарт добавили JSON и CSS модули. В будущем ожидается добавление HTML модулей. Также появилась возможность указывать псевдонимы для путей к модулям с помощью Import maps.
Сегодня многие проекты используют системы сборки для упаковки кода. В кодовых базах таких проектов будет нечто похожее на ESM. Но это не настоящий ESM, а специальный синтаксис инструкций для сборщиков:
Это удобно, но не работает в браузере. Поэтому сборщики выполняют преобразования. Как и во что превращаются импорты под капотом — зависит от сборщика и настроек. Тем не менее, нестандартные импорты можно заставить работать в браузере.
Импорт в браузере — это HTTP-запрос к ресурсу. Запрос можно перехватить с помощью Service Worker. Браузер ожидает валидный JS-модуль, значит Service Worker должен его вернуть в ответ на перехваченный запрос импорта.
Для текстовых форматов (HTML, CSS) проще всего создать модуль, который экспортирует содержимое запрашиваемых файлов в виде строки. Дополнительно HTML можно преобразовать в объект
Само собой, Service Worker должен быть подключен к странице и зарегистрирован до того, как будут обрабатываться нестандартные импорты. Таким образом можно импортировать, в принципе, любые ресурсы, предоставляя их браузеру в виде JS-модулей.
#js
Стандарт ES2015 (ES6) принёс в JS систему модулей — ESM. Те самые
import ... from ..., которые стали неотъемлемой частью разработки на JS. У ESM в браузере есть ограничения:- Путь к модулю должен быть относительным (начинаться с
/, ./, ../) или абсолютным;- Путь к модулю должен заканчиваться именем файла с расширением
.js;- Импортировать можно только JS-модули.
ESM не стоит на месте. Недавно в стандарт добавили JSON и CSS модули. В будущем ожидается добавление HTML модулей. Также появилась возможность указывать псевдонимы для путей к модулям с помощью Import maps.
Сегодня многие проекты используют системы сборки для упаковки кода. В кодовых базах таких проектов будет нечто похожее на ESM. Но это не настоящий ESM, а специальный синтаксис инструкций для сборщиков:
// 'react' — невалидный путь без псевдонима
import React from 'react';
// импорт .css возможен только через with
import styles from './styles.css';
// импорт изображений не поддерживается
import imgUrl from './img.png';
// недопустимый символ ~ в пути
import { someUtil } from '~/src/utils.js';
// glob patterns не поддерживаются
import * as pages from './pages/*/*.js';
// невалидный путь к модулю
import workletUrl from 'worklet:./worklet.js';
// параметр url игнорируется
import assetAsURL from './asset.js?url';
Это удобно, но не работает в браузере. Поэтому сборщики выполняют преобразования. Как и во что превращаются импорты под капотом — зависит от сборщика и настроек. Тем не менее, нестандартные импорты можно заставить работать в браузере.
Импорт в браузере — это HTTP-запрос к ресурсу. Запрос можно перехватить с помощью Service Worker. Браузер ожидает валидный JS-модуль, значит Service Worker должен его вернуть в ответ на перехваченный запрос импорта.
Для текстовых форматов (HTML, CSS) проще всего создать модуль, который экспортирует содержимое запрашиваемых файлов в виде строки. Дополнительно HTML можно преобразовать в объект
DocumentFragment, а CSS в объект CSSStyleSheet.// sw.js
async function createHTMLModule(html) {
return `
const template = document.createElement('template');
template.innerHTML = \`${html}\`;
export default template.content;
`;
}
async function createCSSModule(css) {
return `
const styles = new CSSStyleSheet();
styles.replaceSync(\`${css}\`);
export default styles;
`;
}
self.addEventListener('fetch', (event) => {
const { destination, url } = event.request;
if (destination === 'noscript') {
const response = await self.fetch(url);
const text = await response.text();
let module = text;
if (url.endsWith('.html')) {
module = createHTMLModule(text);
} else if (url.endsWith('.css')) {
module = createCSSModule(text);
}
event.respondWith(
new Response(
module,
{
headers: {
'Content-Type': 'text/javanoscript'
}
}
)
);
}
});
// main.js
import template from './template.html';
import styles from './styles.css';
console.log(template);
// DocumentFragment
console.log(styles);
// CSSStyleSheet
Само собой, Service Worker должен быть подключен к странице и зарегистрирован до того, как будут обрабатываться нестандартные импорты. Таким образом можно импортировать, в принципе, любые ресурсы, предоставляя их браузеру в виде JS-модулей.
#js
🔥16❤5👍5
Anchoreum
Помните Flexbox Froggy и Grid Garden? Это мини-игры, в которых нужно писать код, используя свойства flexbox и grid для прохождения уровней. Отличный способ разобраться с разными свойствами в игровом формате.
По мотивам этих двух игр сделали ещё одну: Anchoreum. Игра предлагает размещать элементы в указанных местах относительно якоря. Для этого нужно использовать новые свойства и директивы из Anchor Positioning API.
API уже доступен в Chromium-браузерах, а к концу года в рамках Interop 2025 появится в Firefox и Safari (уже доступен в Safari Technology Preview 26). Поэтому можно потихоньку знакомиться с API, в том числе через Anchoreum.
#css
Помните Flexbox Froggy и Grid Garden? Это мини-игры, в которых нужно писать код, используя свойства flexbox и grid для прохождения уровней. Отличный способ разобраться с разными свойствами в игровом формате.
По мотивам этих двух игр сделали ещё одну: Anchoreum. Игра предлагает размещать элементы в указанных местах относительно якоря. Для этого нужно использовать новые свойства и директивы из Anchor Positioning API.
API уже доступен в Chromium-браузерах, а к концу года в рамках Interop 2025 появится в Firefox и Safari (уже доступен в Safari Technology Preview 26). Поэтому можно потихоньку знакомиться с API, в том числе через Anchoreum.
#css
Anchoreum
A game for learning CSS anchor positioning
🔥18👍5❤1
JavaScript сломал Интернет (и назвал это прогрессом)
Наткнулся на статью Джоно Олдерсона «JavaScript broke the web (and called it progress)», которая описывает то, о чём я давно думаю. Веб-разработка сместилась в сторону JS, а фреймворки на его основе стали выбором по умолчанию.
Не важно, это интерактивное веб-приложение, блог или интернет-магазин. Инструменты и подходы те же. Обязательно должен быть популярный фреймворк, сборщик, TypeScript, клиентский роутер и SSR с гидратацией, ведь иначе никак.
Мышление «приложениями» приводит к выбору неподходящих инструментов. Проекты усложняются, потребляют больше ресурсов, требуют больше времени на обслуживание и обновление зависимостей, становятся более хрупкими.
Пользователи получают всю мощь современных технологий с мегабайтами JS, белым экраном, спиннерами, не работающей кнопкой «Назад», вкладками на сотни мегабайт памяти. Там, где этого просто не должно быть.
Основу Интернета всё ещё составляют обычные сайты, которые не должны создаваться как SPA. Лэндинги можно делать на базовых технологиях. Можно даже отказаться от зависимостей и не умереть.
Я считаю, что нужно подбирать инструменты под задачу и стремиться к максимальной простоте технологического стека. Использовать возможности браузера и минимизировать количество сторонних зависимостей.
#js
Наткнулся на статью Джоно Олдерсона «JavaScript broke the web (and called it progress)», которая описывает то, о чём я давно думаю. Веб-разработка сместилась в сторону JS, а фреймворки на его основе стали выбором по умолчанию.
Не важно, это интерактивное веб-приложение, блог или интернет-магазин. Инструменты и подходы те же. Обязательно должен быть популярный фреймворк, сборщик, TypeScript, клиентский роутер и SSR с гидратацией, ведь иначе никак.
Мышление «приложениями» приводит к выбору неподходящих инструментов. Проекты усложняются, потребляют больше ресурсов, требуют больше времени на обслуживание и обновление зависимостей, становятся более хрупкими.
Пользователи получают всю мощь современных технологий с мегабайтами JS, белым экраном, спиннерами, не работающей кнопкой «Назад», вкладками на сотни мегабайт памяти. Там, где этого просто не должно быть.
Основу Интернета всё ещё составляют обычные сайты, которые не должны создаваться как SPA. Лэндинги можно делать на базовых технологиях. Можно даже отказаться от зависимостей и не умереть.
Я считаю, что нужно подбирать инструменты под задачу и стремиться к максимальной простоте технологического стека. Использовать возможности браузера и минимизировать количество сторонних зависимостей.
#js
Jono Alderson
JavaScript broke the web (and called it progress)
We replaced simple websites with complex apps nobody asked for. Now it takes a complex build pipeline just to change a headline.
❤18👍13💯5🌚3😱2👎1🥰1
Вложенность в CSS
Препроцессоры CSS впервые предложили концепцию вложенности. Правила можно вкладывать в другие правила, а при сборке они объединяются в одно. Особенно хорошо это работает в сочетании с методологией БЭМ, чтобы избежать дублирования.
Вложенность настолько понравилась разработчикам, что её просили внедрить в CSS. Два года назад это произошло. Теперь во всех современных браузерах есть стандартная вложенность, которая скоро получит статус Widely Available.
Раньше я активно использовал препроцессоры и вложенность. Теперь я предпочитаю стандартный CSS без препроцессоров и плоские селекторы без вложенности. Это вкусовщина, но есть некоторые аргументы.
Усложняется поиск и отладка. Поиск по селектору
Стандартная вложенность отображается в DevTools особым образом, не очень удобным для копирования селектора с целью дальнейшего поиска. Зато она работает как есть, не требует компиляции и карт исходного кода (sourcemaps).
Ухудшается читаемость. При глубокой вложенности код уходит вправо. Ситуация аналогична многоуровневой вложенности блоков кода (
Теряется контекст. При большом количестве вложенных блоков код не помещается на экране, поэтому легко потерять контекст блока верхнего уровня. В современных IDE это не так актуально благодаря sticky-строкам.
Недостаточная поддержка. Стандартная вложенность скоро получит статус Widely Available. Но это всё ещё новая возможность, не все версии браузеров это поддерживают. Поэтому код нужно предварительно обработать.
Необходимость инструментов. Вытекает из предыдущего пункта. Для обработки кода понадобятся инструменты сборки. По возможности я придерживаюсь подхода с минимизацией цепочки инструментов и уменьшения этапов обработки.
Тем не менее, вложенность удобна для медиа-запросов, директив
#css
Препроцессоры CSS впервые предложили концепцию вложенности. Правила можно вкладывать в другие правила, а при сборке они объединяются в одно. Особенно хорошо это работает в сочетании с методологией БЭМ, чтобы избежать дублирования.
Вложенность настолько понравилась разработчикам, что её просили внедрить в CSS. Два года назад это произошло. Теперь во всех современных браузерах есть стандартная вложенность, которая скоро получит статус Widely Available.
Раньше я активно использовал препроцессоры и вложенность. Теперь я предпочитаю стандартный CSS без препроцессоров и плоские селекторы без вложенности. Это вкусовщина, но есть некоторые аргументы.
Усложняется поиск и отладка. Поиск по селектору
.card__heading из DevTools не даст результатов, потому что в коде он будет записан как &__heading, вложенный в .card. Поиск по &__heading может дать много совпадений в разных блоках.Стандартная вложенность отображается в DevTools особым образом, не очень удобным для копирования селектора с целью дальнейшего поиска. Зато она работает как есть, не требует компиляции и карт исходного кода (sourcemaps).
Ухудшается читаемость. При глубокой вложенности код уходит вправо. Ситуация аналогична многоуровневой вложенности блоков кода (
if, for) или вложенным callback-функциям, что приводит к так называемому callback hell.Теряется контекст. При большом количестве вложенных блоков код не помещается на экране, поэтому легко потерять контекст блока верхнего уровня. В современных IDE это не так актуально благодаря sticky-строкам.
Недостаточная поддержка. Стандартная вложенность скоро получит статус Widely Available. Но это всё ещё новая возможность, не все версии браузеров это поддерживают. Поэтому код нужно предварительно обработать.
Необходимость инструментов. Вытекает из предыдущего пункта. Для обработки кода понадобятся инструменты сборки. По возможности я придерживаюсь подхода с минимизацией цепочки инструментов и уменьшения этапов обработки.
Тем не менее, вложенность удобна для медиа-запросов, директив
@starting-style, @counter-style и @property, псевдо-классов и псевдо-элементов. Вложенность также полезна для объединения и группировки стилей.#css
👍18🌚3👎2❤1🤔1😐1
The Grug Brained Developer
Хочу дополнить пост про JS и сложность, который был в понедельник, ссылкой на The Grug Brained Developer. Груг — не очень умный, но опытный разработчик из пещерного века, который рассказывает о сложности в проектах.
В этом вся суть: сложность — плохо. Советую почитать это забавное произведение за авторством Карсона Гросса, автора библиотеки htmx и других проектов с открытым исходным кодом. Есть перевод на русский.
Будьте как Груг.
Хочу дополнить пост про JS и сложность, который был в понедельник, ссылкой на The Grug Brained Developer. Груг — не очень умный, но опытный разработчик из пещерного века, который рассказывает о сложности в проектах.
complexity bad. complexity very bad. complexity very, very bad
В этом вся суть: сложность — плохо. Советую почитать это забавное произведение за авторством Карсона Гросса, автора библиотеки htmx и других проектов с открытым исходным кодом. Есть перевод на русский.
Будьте как Груг.
👍3😁3❤1🫡1
European Accessibility Act в силе
Обычно я не выпускаю посты по выходным, но сегодня особый повод. Сегодня, 28 июня 2025 года, вступает в силу European Accessibility Act — закон о доступности цифровых сервисов и устройств в странах Европейского Союза.
EAA распространяется на широкий спектр продуктов и сервисов:
- Компьютеры: ноутбуки, планшеты, стационарные компьютеры, смартфоны и их операционные системы;
- Терминалы: банкоматы, инфокиоски, вендинговые автоматы, терминалы электронной очереди;
- Связь: VoIP сервисы, мессенджеры, сервисы видео-связи, телефония;
- Телевидение и стриминг: приложения для TV, стриминговые сервисы, онлайн-кинотеатры, видео-сервисы, приставки;
- Транспорт: сервисы покупки и бронирования билетов, терминалы и приложения для оплаты проезда;
- Банки и финансы: банкоматы, банковские сервисы, электронные банкинги, приложения для оплаты;
- Электронное чтение: ePUB файлы, электронные книги, приложения для чтения;
- Электронная коммерция: интернет-магазины, маркетплейсы, торговые площадки;
- Экстренная помощь: сервисы для связи с экстренными службами.
Закон большой и сложный. Но в контексте веба он значит, что если вы разрабатываете сайты или приложения в этих категориях, то они должны соответствовать WCAG 2.1 на уровне AA. В 2026 году ожидается переход на WCAG 2.2.
С применением EAA ожидается рост запросов на доработку веб-сервисов под требования доступности для Европейского рынка. Разработчикам рекомендую подборку ссылок для знакомства с доступной разработкой от Тани Фокиной.
Если вам нужен аудит, консультация или помощь с веб-доступностью, я готов предоставить свою экспертизу: последние 3 года работаю с веб-доступностью в сфере fintech и ecommerce. Обращайтесь в личку: @alexnozer.
#a11y
Обычно я не выпускаю посты по выходным, но сегодня особый повод. Сегодня, 28 июня 2025 года, вступает в силу European Accessibility Act — закон о доступности цифровых сервисов и устройств в странах Европейского Союза.
EAA распространяется на широкий спектр продуктов и сервисов:
- Компьютеры: ноутбуки, планшеты, стационарные компьютеры, смартфоны и их операционные системы;
- Терминалы: банкоматы, инфокиоски, вендинговые автоматы, терминалы электронной очереди;
- Связь: VoIP сервисы, мессенджеры, сервисы видео-связи, телефония;
- Телевидение и стриминг: приложения для TV, стриминговые сервисы, онлайн-кинотеатры, видео-сервисы, приставки;
- Транспорт: сервисы покупки и бронирования билетов, терминалы и приложения для оплаты проезда;
- Банки и финансы: банкоматы, банковские сервисы, электронные банкинги, приложения для оплаты;
- Электронное чтение: ePUB файлы, электронные книги, приложения для чтения;
- Электронная коммерция: интернет-магазины, маркетплейсы, торговые площадки;
- Экстренная помощь: сервисы для связи с экстренными службами.
Закон большой и сложный. Но в контексте веба он значит, что если вы разрабатываете сайты или приложения в этих категориях, то они должны соответствовать WCAG 2.1 на уровне AA. В 2026 году ожидается переход на WCAG 2.2.
С применением EAA ожидается рост запросов на доработку веб-сервисов под требования доступности для Европейского рынка. Разработчикам рекомендую подборку ссылок для знакомства с доступной разработкой от Тани Фокиной.
Если вам нужен аудит, консультация или помощь с веб-доступностью, я готов предоставить свою экспертизу: последние 3 года работаю с веб-доступностью в сфере fintech и ecommerce. Обращайтесь в личку: @alexnozer.
#a11y
❤16😁4🔥3🤩1
You don't know HTML: tabindex
В HTML есть глобальный атрибут
Первоначальная задумка атрибута в том, чтобы указывать порядковый номера элемента в последовательности перехода по интерактивным элементам с помощью клавиш
Это запутывает пользователей, делает клавиатурную навигацию непоследовательной и непредсказуемой. Сегодня
- Реализация техники roving tabindex — навигации с помощью стрелок внутри виджетов, которые подразумевают такую навигацию;
- Добавление возможности программно сфокусироваться на не фокусируемом элементе. Например заголовке
В редких случаях нужно сделать интерактивные элементы временно не фокусируемыми, например в неактивных слайдах карусели. Атрибут
Если вы используете стандартные фокусируемые элементы HTML, не создаёте собственные виджеты на основе ARIA, не реализуете техники клавиатурной навигации и не управляете поведением фокуса из JS, атрибут
#ydkhtml
В HTML есть глобальный атрибут
tabindex, который управляет возможностью фокусировки на элементе при навигации с помощью клавиатуры и порядком элемента в последовательности этой фокусировки.Первоначальная задумка атрибута в том, чтобы указывать порядковый номера элемента в последовательности перехода по интерактивным элементам с помощью клавиш
Tab и Shift+Tab, откуда и название.tabindex всё ещё так работает, но индексы больше 0 считаются плохой практикой. Элементы с tabindex больше 0 переносятся в начало последовательности фокусировки и выстраиваются в своём порядке, что нарушают естественный поток. Это запутывает пользователей, делает клавиатурную навигацию непоследовательной и непредсказуемой. Сегодня
tabindex стоит использовать только со значениями -1 и 0 для решения некоторых задач.tabindex="-1" убирает фокусируемый элемент из последовательности фокусировки, но сохраняет возможность установки фокуса с помощью вызова метода focus() в JS или за счёт атрибута autofocus. Есть два варианта применения:- Реализация техники roving tabindex — навигации с помощью стрелок внутри виджетов, которые подразумевают такую навигацию;
- Добавление возможности программно сфокусироваться на не фокусируемом элементе. Например заголовке
<h1> в SPA или первом элементе <p> внутри модального окна.tabindex="0" делает изначально не фокусируемый элемент фокусируемым и добавляет его в последовательность фокусировки. Это нужно при создании интерактивных пользовательских виджетов на основе паттернов ARIA с требованиями к клавиатурной навигации.В редких случаях нужно сделать интерактивные элементы временно не фокусируемыми, например в неактивных слайдах карусели. Атрибут
inert лучше подходит для этого, так как отключает фокусировку и убирает из дерева доступности.Если вы используете стандартные фокусируемые элементы HTML, не создаёте собственные виджеты на основе ARIA, не реализуете техники клавиатурной навигации и не управляете поведением фокуса из JS, атрибут
tabindex вам не понадобится.#ydkhtml
Web Accessibility Initiative (WAI)
Developing a Keyboard Interface
Accessibility resources free online from the international standards organization: W3C Web Accessibility Initiative (WAI).
👍14❤3🔥2
Web Awesome beta
Вышла первая бета-версия проекта Web Awesome — ребрендинга и следующей мажорной версия библиотеки веб-компонентов Shoelace. Я активно использую её на разных проектах и часто рекомендую. Есть даже соответствующий пост.
Создатель и основной ментейнер Shoelace, Кори ЛаВиска, в 2022 году присоединился к команде Font Awesome — популярной библиотеки иконок. В 2024 году была проведена успешная кампания на Kickstarter по сбору средств на разработку Web Awesome.
Результатом стал полный ребрендинг Shoelace с новым названием, визуальным оформлением и функциями. Web Awesome по-прежнему останется библиотекой с открытым исходным кодом. Всё, что доступно в Shoelace будет доступно в Web Awesome.
С ребрендингом переработано ядро библиотеки. Улучшен механизм стилизации и темизации, доработаны существующие и добавлены новые компоненты, исправлены баги. Список изменений внушительный.
Из нового: утилиты для раскладки, две новые темы (Default и Web Awesome, старая сохранена под названием Shoelace), стили для стандартных HTML-элементов, визуальные тесты для поддержания консистентности, дополнительные дизайн-токены.
Для поддержания устойчивости проекта появились варианты платных подписок с расширенными функциями:
- Редактор тем. Возможность создать собственную уникальную тему через веб-интерфейс и выгрузить её для использования в проекте;
- Библиотека шаблонов. Набор готовых популярных шаблонов пользовательского интерфейса, собранных из компонентов библиотеки;
- Компонент страницы. Специальный настраиваемый компонент для расположения основных элементов страницы и создания адаптивного макета;
- Иконки Font Awesome. Быстрое добавление в проект иконок Font Awesome Pro при наличии соответствующей подписки;
- Темы и компоненты. Дополнительные темы и компоненты, такие как Data Grid, Chart, Combobox, Date Picker;
На данный момент Web Awesome вышла в стадию публичной беты после этапа альфа-тестирования. Работа продолжается, в том числе некоторые обновления отправляются в текущую 2.x версию Shoelace.
Платные функции и поддержка со стороны Font Awesome делают проект устойчивым. Ядро остаётся бесплатным и с открытым кодом. Разработка на основе веб-стандартов обеспечивает долговечность и совместимость практически с любым стеком.
#ui
Вышла первая бета-версия проекта Web Awesome — ребрендинга и следующей мажорной версия библиотеки веб-компонентов Shoelace. Я активно использую её на разных проектах и часто рекомендую. Есть даже соответствующий пост.
Создатель и основной ментейнер Shoelace, Кори ЛаВиска, в 2022 году присоединился к команде Font Awesome — популярной библиотеки иконок. В 2024 году была проведена успешная кампания на Kickstarter по сбору средств на разработку Web Awesome.
Результатом стал полный ребрендинг Shoelace с новым названием, визуальным оформлением и функциями. Web Awesome по-прежнему останется библиотекой с открытым исходным кодом. Всё, что доступно в Shoelace будет доступно в Web Awesome.
С ребрендингом переработано ядро библиотеки. Улучшен механизм стилизации и темизации, доработаны существующие и добавлены новые компоненты, исправлены баги. Список изменений внушительный.
Из нового: утилиты для раскладки, две новые темы (Default и Web Awesome, старая сохранена под названием Shoelace), стили для стандартных HTML-элементов, визуальные тесты для поддержания консистентности, дополнительные дизайн-токены.
Для поддержания устойчивости проекта появились варианты платных подписок с расширенными функциями:
- Редактор тем. Возможность создать собственную уникальную тему через веб-интерфейс и выгрузить её для использования в проекте;
- Библиотека шаблонов. Набор готовых популярных шаблонов пользовательского интерфейса, собранных из компонентов библиотеки;
- Компонент страницы. Специальный настраиваемый компонент для расположения основных элементов страницы и создания адаптивного макета;
- Иконки Font Awesome. Быстрое добавление в проект иконок Font Awesome Pro при наличии соответствующей подписки;
- Темы и компоненты. Дополнительные темы и компоненты, такие как Data Grid, Chart, Combobox, Date Picker;
На данный момент Web Awesome вышла в стадию публичной беты после этапа альфа-тестирования. Работа продолжается, в том числе некоторые обновления отправляются в текущую 2.x версию Shoelace.
Платные функции и поддержка со стороны Font Awesome делают проект устойчивым. Ядро остаётся бесплатным и с открытым кодом. Разработка на основе веб-стандартов обеспечивает долговечность и совместимость практически с любым стеком.
#ui
Web Awesome
Build better with Web Awesome, the biggest open-source library of meticulously designed, highly customizable, and framework-agnostic UI components.
👍4❤1
Кнопка «наверх»
Один из распространённых паттернов в интернете — кнопка «наверх», которая плавно прокручивает страницу к началу. Обычно для этого используется JS-плагин или пишется небольшой скрипт с вызовом метода
Темани Афиф придумал способ сделать такую кнопку на CSS. Понадобится grid, sticky-позиционирование и немного хитростей. Вот весь код:
В
Получается то что нужно: вверху страницы кнопка не видна, но появляется при прокрутке на указанное в
В качестве «кнопки» используется элемент ссылки
Свойство
Получается вполне интересное, не сложное и функциональное решение для кнопки «наверх» без применения JS. Подробнее о нём можно почитать в статье Темани Афифа «How to Make an Animated Back to Top Button Using Only CSS».
#css #ui
Один из распространённых паттернов в интернете — кнопка «наверх», которая плавно прокручивает страницу к началу. Обычно для этого используется JS-плагин или пишется небольшой скрипт с вызовом метода
scroll* и Web Animations API.Темани Афиф придумал способ сделать такую кнопку на CSS. Понадобится grid, sticky-позиционирование и немного хитростей. Вот весь код:
<body>
<div>
<header id="top">
<!-- шапка страницы -->
</header>
<!-- остальной контент -->
</div>
<a href="#top">Наверх</a>
</body>
body {
display: grid;
grid-template-columns: auto 0px;
}
@media (prefers-reduced-motion: no-preference) {
body {
scroll-behavior: smooth;
}
}
a[href="#top"] {
--offset: 50px;
position: sticky;
bottom: 20px;
margin-right: 10px;
place-self: end;
margin-top: calc(100vh + var(--offset));
}В
<body> создаётся сетка из двух колонок: для контента и кнопки. Колонка с кнопкой получает нулевую ширину. Кнопка смещается на высоту области просмотра и ещё некоторое дополнительное расстояние. При прокрутке прилипает к нижней части экрана.Получается то что нужно: вверху страницы кнопка не видна, но появляется при прокрутке на указанное в
--offset расстояние и прилипает к нижней части страницы. Саму кнопку при этом можно свободно стилизовать.В качестве «кнопки» используется элемент ссылки
<a> с фрагментом #top. При нажатии браузер прокрутит страницу к элементу с атрибутом id="top", в примере это <header>. Причём не просто прокрутит, а перенесёт туда фокус.Свойство
scroll-behavior: smooth у <body> сделает прокрутку плавной, но только если пользователь не предпочёл уменьшить количество движений в настройках ОС. Пользовательские предпочтения нужно уважать.Получается вполне интересное, не сложное и функциональное решение для кнопки «наверх» без применения JS. Подробнее о нём можно почитать в статье Темани Афифа «How to Make an Animated Back to Top Button Using Only CSS».
#css #ui
freeCodeCamp.org
How to Make an Animated Back to Top Button Using Only CSS
Having a "back to top" button on a website is important. It allows users to easily scroll back to the top of the page. Most websites rely on JavaScript to toggle the visibility of the button based on the amount of scroll. In this post, I will show y...
🔥24❤10👍4
Преимущества доступности для разработчиков
Конечные получатели выгоды от доступности — пользователи с ограниченными возможностями. Но Нолан Лоусон приводит свои эгоистичные причины создания доступных интерфейсов с преимуществами для разработчиков.
Отладка
Когда разметка состоит из
Именование
«Автокомплит»? «Дропдаун»? «Пикер»? Члены команды могут использовать разные названия для UI-элементов. Руководство ARIA предлагает названия для распространённых UI-элементов, чтобы говорить на одном языке.
Состояния
Часто состояния элементов задаются в виде динамически изменяемых CSS-классов:
Тестирование
В UI-тестировании для поиска элементов используются классы, текст и
Опытные пользователи
Многие профессиональные пользователи используют клавиатуру при взаимодействии с интерфейсом для ускорения работы. Доступные UI-элементы с клавиатурной навигацией позволяют пользоваться интерфейсом быстрее.
***
От доступности выигрывают не только пользователи с ограниченными возможностями, но также разработчики, тестировщики и пользователи без ограничений здоровья. Это ещё один довод в пользу внедрения доступности.
#a11y #ux
Конечные получатели выгоды от доступности — пользователи с ограниченными возможностями. Но Нолан Лоусон приводит свои эгоистичные причины создания доступных интерфейсов с преимуществами для разработчиков.
Отладка
Когда разметка состоит из
<div>-ов с нечитаемыми хэш-классами, в ней трудно ориентироваться и находить нужные элементы при отладке. Семантическая разметка с ARIA-атрибутами более читаемая и удобная для отладки в браузере.Именование
«Автокомплит»? «Дропдаун»? «Пикер»? Члены команды могут использовать разные названия для UI-элементов. Руководство ARIA предлагает названия для распространённых UI-элементов, чтобы говорить на одном языке.
Состояния
Часто состояния элементов задаются в виде динамически изменяемых CSS-классов:
current, selected, has-dropdown. Вместо них можно использовать ARIA-атрибуты: aria-current="page", aria-selected="true", aria-haspopup="true".Тестирование
В UI-тестировании для поиска элементов используются классы, текст и
data-* атрибуты. При семантической разметке c ARIA-атрибутами в качестве якорей можно использовать роли, состояния и свойства элементов. Об этом есть свежий доклад.Опытные пользователи
Многие профессиональные пользователи используют клавиатуру при взаимодействии с интерфейсом для ускорения работы. Доступные UI-элементы с клавиатурной навигацией позволяют пользоваться интерфейсом быстрее.
***
От доступности выигрывают не только пользователи с ограниченными возможностями, но также разработчики, тестировщики и пользователи без ограничений здоровья. Это ещё один довод в пользу внедрения доступности.
#a11y #ux
Read the Tea Leaves
Selfish reasons for building accessible UIs
All web developers know, at some level, that accessibility is important. But when push comes to shove, it can be hard to prioritize it above a bazillion other concerns when you’re trying to c…
👍13❤3🔥2
Используем новые возможности веба в привычной разработке
Предлагаю запись доклада Александра Нефедова, в котором рассказывается о применении новых возможностей веб-платформы в привычной разработке. Будет полезно тем, кто давно в профессии и привык делать по-старинке.
В докладе освещаются следующие возможности:
-
-
-
-
- Альтернативный текст в
-
-
-
-
- View Transitions;
- Intl;
-
-
- CSS Nesting;
- LightningCSS, esbuild, Vite;
- P3,
Что-то из этого не такое новое и уже давно доступно во всех браузерах. Что-то более новое, но может использоваться как прогрессивное улучшение.
#html #css #js #web_api
Предлагаю запись доклада Александра Нефедова, в котором рассказывается о применении новых возможностей веб-платформы в привычной разработке. Будет полезно тем, кто давно в профессии и привык делать по-старинке.
В докладе освещаются следующие возможности:
-
image-set();-
:focus-visible;-
min-content, fit-content, max-content;-
text-wrap: balance;- Альтернативный текст в
content;-
field-sizing: content;-
::target-text;-
scroll-behavior: smooth;-
scrollbar-gutter;- View Transitions;
- Intl;
-
<dialog>;-
enterkeyhint;- CSS Nesting;
- LightningCSS, esbuild, Vite;
- P3,
oklch().Что-то из этого не такое новое и уже давно доступно во всех браузерах. Что-то более новое, но может использоваться как прогрессивное улучшение.
#html #css #js #web_api
YouTube
Александр Нефедов — Используем новые возможности веба в привычной разработке
Подробнее о конференции HolyJS: https://jrg.su/EM4wwV
— —
Скачать презентацию с сайта HolyJS — https://jrg.su/BTvhbG
В браузерах постоянно появляется что-то новое, а профессия «фронтендер» все больше считается устоявшейся. В докладе пробуем расшатать устои…
— —
Скачать презентацию с сайта HolyJS — https://jrg.su/BTvhbG
В браузерах постоянно появляется что-то новое, а профессия «фронтендер» все больше считается устоявшейся. В докладе пробуем расшатать устои…
👍15❤6
if() в CSS
Год назад я писал о том, что рабочая группа CSS приняла решение о добавлении функции if(). В недавно вышедшей 137й версии Chrome и Edge появилась поддержка if(). Хотя я скептически отношусь к этому нововведению, оно стоит внимания.
Функция
На данный момент в качестве условия можно применить одну из трёх функций:
-
-
-
Синтаксис функции
Наиболее интересна функция
Все иконки указаны в одном месте и зависят от цвета текста. В противном случае определять иконки нужно у каждого класса-модификатора. Объём кода в обоих случаях будет плюс-минус сопоставимым, но с
Пользовательские свойства позволяют определять произвольные характеристики элементов и их значения. Это можно использовать в сочетании с функцией
Все стили тоста определяются в одном месте, а модификаторы задают только значения пользовательского свойства. Это чем-то похоже на пропсы во фреймворках. С
Несмотря на мой скепсис по поводу
Так как синтаксис
#css
Год назад я писал о том, что рабочая группа CSS приняла решение о добавлении функции if(). В недавно вышедшей 137й версии Chrome и Edge появилась поддержка if(). Хотя я скептически отношусь к этому нововведению, оно стоит внимания.
Функция
if() позволяет задавать разные значения свойств в зависимости от условий или резервное значение, если ни одно из условий не выполняется. Количество условий не ограничено, а резервное значение не обязательно. Базовый синтаксис такой:selector {
property: if(
condition-1: value-1;
condition-2: value-2;
else: value-3
);
}На данный момент в качестве условия можно применить одну из трёх функций:
-
media() — привычные медиа-запросы, аналогичные директиве @media;-
supports() — запросы поддержки функций, аналогичные директиве @supports;-
style() — запросы стиля, которые недавно стали доступны в рамках директивы @container.Синтаксис функции
if() заменяет директивы @media, @supports и @container в тех случаях, когда нужно использовать другие значения отдельных свойств при выполнении условия директивы. С if() код получается короче:/* Подход с переопределением */
.card {
padding: 2rem;
}
@media (width < 600px) {
.card {
padding: 1rem;
}
}
/* Подход с вложенностью */
.card {
padding: 2rem;
@media (width < 600px) {
padding: 1rem;
}
}
/* Подход с if() */
.card {
padding: if(
media(width < 600px): 1rem; else: 2rem
);
}
Наиболее интересна функция
style(), которая позволяет проверять значения стандартных и пользовательских свойств. Так, в зависимости от цвета текста можно менять иконку в компоненте, вроде тоста, примечания или уведомления:.toast {
background-image: if(
style(color: green): url('/success.noscript');
style(color: orange): url('/warning.noscript');
style(color: red): url('/danger.noscript');
else: url('/info.noscript')
);
}
.toast--success {
color: green;
}
.toast--warning {
color: orange;
}
.toast--danger {
color: red;
}Все иконки указаны в одном месте и зависят от цвета текста. В противном случае определять иконки нужно у каждого класса-модификатора. Объём кода в обоих случаях будет плюс-минус сопоставимым, но с
if() иконки описаны в одном месте.UPD 03.08.25: style() может принимать обычные свойства, но пока поддерживаются только пользовательские свойства. Пример выше не будет работать.
Пользовательские свойства позволяют определять произвольные характеристики элементов и их значения. Это можно использовать в сочетании с функцией
if() для создания различных вариантов компонентов с разными стилями:.toast {
background-image: if(
style(--variant: success): url('/success.noscript');
style(--variant: warning): url('/warning.noscript');
style(--variant: danger): url('/danger.noscript');
else: url('/info.noscript')
);
color: if(
style(--variant: success): green;
style(--variant: warning): orange;
style(--variant: danger): red;
else: lightblue
);
}
.toast--success {
--variant: success;
}
.toast--warning {
--variant: warning;
}
.toast--danger {
--variant: danger;
}Все стили тоста определяются в одном месте, а модификаторы задают только значения пользовательского свойства. Это чем-то похоже на пропсы во фреймворках. С
if() и обновлённой функцией attr() можно обойтись без модификаторов:<style>
.toast {
--variant: attr(data-variant type(<custom-ident>), default);
/* свойства с if() */
}
</style>
<!-- установка --variant через атрибут style -->
<div class="toast" style="--variant: danger">
<!-- danger тост -->
</div>
<!-- установка --variant через data-атрибут -->
<div class="toast" data-variant="success">
<!-- success тост -->
</div>
Несмотря на мой скепсис по поводу
if(), стилизация компонентов с указанием пользовательских свойств в style или data-* атрибутах и проверкой их значений в одном месте выглядит интересно.Так как синтаксис
if() можно откатить к директивам @media, @supports и @container, его уже скоро можно будет использовать в сочетании с PostCSS или LightningCSS. Пока в них нет соответствующих преобразований, но это лишь вопрос времени.#css
Chrome for Developers
CSS conditionals with the new if() function | Blog | Chrome for Developers
Learn about the new CSS if function, which enables a cleaner developer interface for dynamic styles like style queries and media queries.
❤10🤔3🤯2😐2
Bootstrap нового поколения
Две недели назад выкатили бета-версию Web Awesome — новую мажорную версию библиотеки веб-компонентов Shoelace. Я делал пост об этом и в процессе написания у меня возникла мысль, что Web Awesome — это Bootstrap нового поколения.
Bootstrap — это популярная библиотека с утилитами, раскладками, сеткой, шаблонами распространённых элементов интерфейса и интерактивными компонентами с возможностью гибкой конфигурации.
Всё это не привязано к какому-то фреймворку и подключается к сайту с помощью
Bootstrap жив и активно развивается, вопреки некоторым мнениям. Текущая версия 5.3.7 вышла 10 июня. В разработке находится 6-я мажорная версия. Bootstrap активно используется: 5.4 млн. установок с npm, не считая загрузок с CDN.
И тут на сцену выходит Web Awesome с утилитами, раскладками, сеткой, шаблонами распространённых элементов интерфейса, интерактивными компонентами, установкой через npm или CDN, возможностью собственной сборки и токенами.
Web Awesome постепенно догоняет Bootstrap по возможностям, но использует более современные возможности браузеров. Это решает некоторые проблемы Bootstrap и делает библиотеку удобнее в использовании.
Вместо копирования вёрстки — пользовательские элементы. Вместо настройки через SCSS — темы на основе пользовательских свойств. Стили компонентов изолированы, никакой борьбы с переопределением.
Поэтому для меня Web Awesome выглядит как Bootstrap нового поколения. В ту же сторону стоило бы двигаться и самому Bootstrap. Посмотрим, каким будет Web Awesome после беты и что выкатят в 6-й версии Bootstrap.
#css #ui
Две недели назад выкатили бета-версию Web Awesome — новую мажорную версию библиотеки веб-компонентов Shoelace. Я делал пост об этом и в процессе написания у меня возникла мысль, что Web Awesome — это Bootstrap нового поколения.
Bootstrap — это популярная библиотека с утилитами, раскладками, сеткой, шаблонами распространённых элементов интерфейса и интерактивными компонентами с возможностью гибкой конфигурации.
Всё это не привязано к какому-то фреймворку и подключается к сайту с помощью
<link> и <noscript>. Есть возможность установки через npm, чтобы собрать и настроить собственную версию с нужными токенами и файлами.Bootstrap жив и активно развивается, вопреки некоторым мнениям. Текущая версия 5.3.7 вышла 10 июня. В разработке находится 6-я мажорная версия. Bootstrap активно используется: 5.4 млн. установок с npm, не считая загрузок с CDN.
И тут на сцену выходит Web Awesome с утилитами, раскладками, сеткой, шаблонами распространённых элементов интерфейса, интерактивными компонентами, установкой через npm или CDN, возможностью собственной сборки и токенами.
Web Awesome постепенно догоняет Bootstrap по возможностям, но использует более современные возможности браузеров. Это решает некоторые проблемы Bootstrap и делает библиотеку удобнее в использовании.
Вместо копирования вёрстки — пользовательские элементы. Вместо настройки через SCSS — темы на основе пользовательских свойств. Стили компонентов изолированы, никакой борьбы с переопределением.
Поэтому для меня Web Awesome выглядит как Bootstrap нового поколения. В ту же сторону стоило бы двигаться и самому Bootstrap. Посмотрим, каким будет Web Awesome после беты и что выкатят в 6-й версии Bootstrap.
#css #ui
👏13🔥5❤1