sizes="auto" для изображений
Для адаптивных изображений у элемента
В Firefox 150 и Chrome 124 добавили новое значение
Зачем указывать
Обнаружив изображение, браузер поместит его в очередь загрузки. В моменте нужно решить, какое из изображений ставить в очередь. К этому времени стили могут быть ещё не загружены или не обработаны. Поэтому браузер смотрит значение
С лениво-загружаемыми изображениями ситуация другая. Их загрузка отложена до тех пор, пока изображение не появится в области просмотра. Чтобы это выяснить, браузеру нужно обработать стили и знать размеры и положение на странице.
К моменту загрузки ленивого изображения, даже если оно находится на первом экране, браузер уже обработал стили и знает все размеры. Именно поэтому
Таким образом изображениям с ленивой загрузкой
Синтаксисом предусмотрено совмещение значения
Мэт Маркиз, бывший председатель группы адаптивных изображений (Responsive Image Community Group) написал статью «The end of responsive images», в которой рассказал более чем 10-летнюю историю появления
#html #css
Для адаптивных изображений у элемента
<img> есть два атрибута. srcset задаёт набор изображений с физической шириной или плотностью пикселей. sizes задаёт доступное пространство, которое браузер заполняет подходящим изображением.В Firefox 150 и Chrome 124 добавили новое значение
sizes="auto". Однако не стоит думать, что теперь указывать размеры в sizes не нужно. sizes="auto" работает в паре с loading="lazy". Без него указывать auto нет смысла, работать не будет.Зачем указывать
sizes, разве браузер не знает размеры области для отрисовки изображения? Дело в том, что не знает до загрузки и обработки всех стилей. Сканер предварительной загрузки анализирует HTML и ищет ресурсы.Обнаружив изображение, браузер поместит его в очередь загрузки. В моменте нужно решить, какое из изображений ставить в очередь. К этому времени стили могут быть ещё не загружены или не обработаны. Поэтому браузер смотрит значение
sizes.С лениво-загружаемыми изображениями ситуация другая. Их загрузка отложена до тех пор, пока изображение не появится в области просмотра. Чтобы это выяснить, браузеру нужно обработать стили и знать размеры и положение на странице.
К моменту загрузки ленивого изображения, даже если оно находится на первом экране, браузер уже обработал стили и знает все размеры. Именно поэтому
sizes="auto" будет работать, браузер возьмёт известные ему размеры области.Таким образом изображениям с ленивой загрузкой
loading="lazy" можно задать sizes="auto". Остальным всё ещё нужно указывать размеры. Также остаются браузеры, которые не понимают значение auto, для них тоже нужны размеры.Синтаксисом предусмотрено совмещение значения
auto с размерами. Если браузер не понимает auto или не может получить размеры из стилей, он откатится к размеру, который указан после auto через запятую: sizes="auto, (min-width: 600px) 50vw, 90vw".Мэт Маркиз, бывший председатель группы адаптивных изображений (Responsive Image Community Group) написал статью «The end of responsive images», в которой рассказал более чем 10-летнюю историю появления
sizes="auto".#html #css
Piccalilli
The end of responsive images
Mat Marquis has waited 14 years to write this article. The sizes attribute has been a necessary evil but now, with an auto value capability, it’s completely transformed authoring responsive images on the web.
👍5🔥3❤1🌚1🤝1
ARIA APG: доверяй, но проверяй
Есть ресурс под названием ARIA Authoring Practices Guide, сокращённо APG. На него ссылаются как на источник доступных шаблонов элементов интерфейса. Это неплохой ресурс, но при обращении к нему стоит помнить о некоторых нюансах.
Ресурс выглядит официально, содержит логотип W3C и WAI, размещён на домене w3.org, упоминается на сайте инициативы по веб доступности. Внушает доверие и вызвает ложное ощущение официального стандарта от W3C.
На деле APG — не стандарт W3C, в отличие от ARIA, WCAG, ARIA in HTML и других. APG создан специальной группой APG Task Force из сообщества WAI, которое, в свою очередь, одно из многих сообществ в составе консорциума W3C.
Задача APG — показать, как применять стандарт ARIA для реализации элементов интерфейса. Шаблоны демонстрируют все роли, свойства и состояния в соответствии с правилами стандарта. Это своего рода витрина ARIA.
Если взглянуть на шаблон кнопки, то APG предлагает использовать
Тем временем первое правило ARIA гласит, что не стоит использовать ARIA, если есть встроенный элемент. В HTML кнопка есть —
Аналогично с шаблонами флажков, радио-кнопок, диалогов, раскрываемых блоков, ссылок, ориентиров, шкалы, слайдера, таблиц и так далее. Они показывают, как реализовать с помощью ARIA. Зачастую в этом нет необходимости.
Отдельного внимания заслуживает борьба Адриана Розелли с шаблоном навигации сайта, который долгое время предлагал использовать не подходящие роли меню. Разработчики внедряли этот шаблон на сайты и делали только хуже.
Всё сказанное выше не значит, что на APG не стоит смотреть. Это неплохой источник информации о проектировании доступных интерфейсов. Важно не воспринимать его как официальный источник истины со 100% правильными шаблонами.
Эрик Бэйли считает хорошими частями в APG:
- Названия шаблонов. Хорошо, когда вся команда говорит на одном языке;
- Описания шаблонов. Суть шаблона, для чего нужен, как работает и когда применять;
- Клавиатурная навигация. Клавиши и их сочетания, которые должны работать при взаимодействии;
Остальное вторично. Таблицы поддержки не отражают реальный уровень поддержки, примеры кода не согласованы, написаны в разных стилях, используют устаревшие подходы и не готовы к продакшену, часть шаблонов заменяется встроенным HTML.
Используйте APG как источник знаний о сути того или иного шаблона и навигации с помощью клавиатуры. По возможности используйте встроенные HTML-элементы, обращайтесь к официальному стандарту ARIA и всегда тестируйте.
#ui #a11y
Есть ресурс под названием ARIA Authoring Practices Guide, сокращённо APG. На него ссылаются как на источник доступных шаблонов элементов интерфейса. Это неплохой ресурс, но при обращении к нему стоит помнить о некоторых нюансах.
Ресурс выглядит официально, содержит логотип W3C и WAI, размещён на домене w3.org, упоминается на сайте инициативы по веб доступности. Внушает доверие и вызвает ложное ощущение официального стандарта от W3C.
На деле APG — не стандарт W3C, в отличие от ARIA, WCAG, ARIA in HTML и других. APG создан специальной группой APG Task Force из сообщества WAI, которое, в свою очередь, одно из многих сообществ в составе консорциума W3C.
Задача APG — показать, как применять стандарт ARIA для реализации элементов интерфейса. Шаблоны демонстрируют все роли, свойства и состояния в соответствии с правилами стандарта. Это своего рода витрина ARIA.
Если взглянуть на шаблон кнопки, то APG предлагает использовать
<div>, <a> и <span> с ролью button, tabindex="0" для фокуса и JS для обработки нажатия. APG свою задачу выполнил: показал, как использовать роль button.Тем временем первое правило ARIA гласит, что не стоит использовать ARIA, если есть встроенный элемент. В HTML кнопка есть —
<button>. На практике <div> с ролью кнопки, tabindex и обработчиком нажатий считается антипаттерном.Аналогично с шаблонами флажков, радио-кнопок, диалогов, раскрываемых блоков, ссылок, ориентиров, шкалы, слайдера, таблиц и так далее. Они показывают, как реализовать с помощью ARIA. Зачастую в этом нет необходимости.
Отдельного внимания заслуживает борьба Адриана Розелли с шаблоном навигации сайта, который долгое время предлагал использовать не подходящие роли меню. Разработчики внедряли этот шаблон на сайты и делали только хуже.
Всё сказанное выше не значит, что на APG не стоит смотреть. Это неплохой источник информации о проектировании доступных интерфейсов. Важно не воспринимать его как официальный источник истины со 100% правильными шаблонами.
Эрик Бэйли считает хорошими частями в APG:
- Названия шаблонов. Хорошо, когда вся команда говорит на одном языке;
- Описания шаблонов. Суть шаблона, для чего нужен, как работает и когда применять;
- Клавиатурная навигация. Клавиши и их сочетания, которые должны работать при взаимодействии;
Остальное вторично. Таблицы поддержки не отражают реальный уровень поддержки, примеры кода не согласованы, написаны в разных стилях, используют устаревшие подходы и не готовы к продакшену, часть шаблонов заменяется встроенным HTML.
Используйте APG как источник знаний о сути того или иного шаблона и навигации с помощью клавиатуры. По возможности используйте встроенные HTML-элементы, обращайтесь к официальному стандарту ARIA и всегда тестируйте.
#ui #a11y
1👍6❤5🔥3⚡1🌚1😎1
Переусложнённые радио-кнопки в Shadcn
Пол Геберт в блоге написал о чрезмерно переусложнённых радио-кнопках в Shadcn. Это библиотека готовых компонентов для React, которая построена на базе Radix UI, использует Tailwind и работает по принципу «copy-paste» кода в проект.
Предположим, что в проекте нужны радио-кнопки. В HTML это решается добавлением
Если залезать под капот импортируемого
Радио-кнопка в Shadcn — это кнопка с ARIA-атрибутами для имитации радио-кнопки, SVG-круг, скрытый
Применение
Задумка Shadcn и Radix, по всей видимости, в надёжности стилизации. С
#html #css #ui
Пол Геберт в блоге написал о чрезмерно переусложнённых радио-кнопках в Shadcn. Это библиотека готовых компонентов для React, которая построена на базе Radix UI, использует Tailwind и работает по принципу «copy-paste» кода в проект.
Предположим, что в проекте нужны радио-кнопки. В HTML это решается добавлением
<input type="radio">. В Shadcn для этого нужно 3 импорта, 45 строк кода, сторонняя библиотека иконок для кружка, 30 классов Tailwind.Если залезать под капот импортируемого
RadioGroupPrimitive, там ещё 215 строк кода и 7 импортов. Неужели для радио-кнопок нужно столько кода? Но это ладно. Какой результат получается в браузере при отрисовке этого всего?<button
id="debit"
class="классы Tailwind"
type="button"
role="radio"
aria-checked="true"
data-state="checked"
value="debit"
tabindex="0"
data-radix-collection-item
>
<span
class="классы Tailwind"
data-state="checked"
>
<svg
class="классы Tailwind"
xmlns="..."
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10">
</circle>
</svg>
</span>
</button>
<input
aria-hidden="true"
style="..."
tabindex="-1"
type="radio"
value="debit"
checked
name="credit-or-debit"
>
Радио-кнопка в Shadcn — это кнопка с ARIA-атрибутами для имитации радио-кнопки, SVG-круг, скрытый
<input type="radio">, который нужен для работы форм и классы Tailwind. Всё может быть гораздо проще, если использовать стандартный HTML:<input
type="radio"
name="credit-or-debit"
value="debit"
checked
>
Применение
appearance: none к флажкам и радио-кнопкам сбрасывает их стандартный внешний вид. После этого можно задавать размеры, фон, рамку, тень, закругление и так далее. Маркеры можно сделать при помощи псевдо-элементов.<input
type="radio"
name="credit-or-debit"
value="debit"
checked
>
<style>
input[type="radio"] {
--color: currentColor;
appearance: none;
display: inline-grid;
place-content: center;
width: 24px;
height: 24px;
border: 2px solid var(--color);
border-radius: 50%;
margin: 0;
&::before {
content: '';
width: 12px;
height: 12px;
border-radius: 50%;
background-color: transparent;
transition: background-color .3s;
}
&:checked::before {
background-color: var(--color);
}
@media (forced-colors: active) {
--color: ButtonText;
}
}
</style>
Задумка Shadcn и Radix, по всей видимости, в надёжности стилизации. С
<input> дела обстоят хуже, чем с <button>. Но всё же решение с appearance работает сегодня во всех актуальных браузерах. Тогда к чему весь этот оверинжиниринг?#html #css #ui
Paulmakeswebsites
The Incredible Overcomplexity of the Shadcn Radio Button
Radio buttons are built into web browsers. Why are we using a UI library that wraps another UI library that rebuilds radio buttons from scratch? Why does rendering a radio button require multiple dependencies and several kilobytes of JavaScript? How did we…
🔥11👍5❤4🌚4👨💻1
Маркетинговый сайт, веб-компоненты и nanotags
Павел Гринченко в блоге Злых Марсиан описал способ разработки маркетинговых сайтов с использованием веб-компонентов и разработанного для них инструмента под названием nanotags, в основе которого другое решение от Марсиан — nanostores.
Маркетинговый сайт — это не приложение с тяжёлой логикой и большим количеством интерактивности. Это статический контент с точечными интерактивными элементами. Такие сайты создаются с использованием генераторов статики, в частности Astro.
Остаётся вопрос с тем, как добавлять ту самую интерактивность. Павел считает API веб-компонентов, встроенные в браузеры, полезными для этой задачи. Но в сыром виде API низкоуровневые и многословные. Поэтому была создана библиотека nanotags.
Это лёгкая библиотека, которая добавляет декларативный способ создания пользовательских элементов, поиска узлов, объявления реактивных свойств на основе nanostores и обработки событий. Цель — скрыть шаблонный код под капот.
nanotags рассчитан на работу с готовой разметкой, генерируемой на сервере или при сборке. Шаблонизатор отсутствует, Shadow DOM не используется. Это отличает nanotags от популярной библиотеки для веб-компонентов — Lit.
В разметке пользовательский элемент
Затем подключается nanotags. Функция
В
Библиотека хорошо интегрирована с TypeScript, выводит типы, поддерживает Standard Schema валидаторы (Valibot, Zod, ArkType) для свойств, работает с данными в формате JSON, делает проверки в рантайме на основе схем.
Больше возможностей nanotags описано в документации. Это интересный взгляд на то, как работать с веб-компонентами. Миграция сэкономила 100кб JS, что хорошо и позволяет лучше вписываться в бюджеты производительности.
Также я обратил внимание, что библиотека разработана с уважением к стандарту HTML. Ссылки на элементы отмечаются атрибутом
Маленькая деталь, которая, тем не менее, отражает отношение автора к стандартам. Все синтаксические расширения выполнены в соответствии с правилами расширения HTML, без выдуманного синтаксиса с невалидной разметкой. За это от меня респект.
#js #tools
Павел Гринченко в блоге Злых Марсиан описал способ разработки маркетинговых сайтов с использованием веб-компонентов и разработанного для них инструмента под названием nanotags, в основе которого другое решение от Марсиан — nanostores.
Маркетинговый сайт — это не приложение с тяжёлой логикой и большим количеством интерактивности. Это статический контент с точечными интерактивными элементами. Такие сайты создаются с использованием генераторов статики, в частности Astro.
Остаётся вопрос с тем, как добавлять ту самую интерактивность. Павел считает API веб-компонентов, встроенные в браузеры, полезными для этой задачи. Но в сыром виде API низкоуровневые и многословные. Поэтому была создана библиотека nanotags.
Это лёгкая библиотека, которая добавляет декларативный способ создания пользовательских элементов, поиска узлов, объявления реактивных свойств на основе nanostores и обработки событий. Цель — скрыть шаблонный код под капот.
nanotags рассчитан на работу с готовой разметкой, генерируемой на сервере или при сборке. Шаблонизатор отсутствует, Shadow DOM не используется. Это отличает nanotags от популярной библиотеки для веб-компонентов — Lit.
<my-counter count="0">
<span data-ref="display">0</span>
<button data-ref="button">+1</button>
</my-counter>
<script>
import { define } from "nanotags"
define("my-counter")
.withProps(p => ({
count: p.number(0)
}))
.withRefs(r => ({
display: r.one("span"),
button: r.one("button")
}))
.setup(ctx => {
ctx.on(ctx.refs.button, "click", () => {
ctx.props.$count.set(ctx.props.$count.get() + 1)
})
ctx.effect(ctx.props.$count, val => {
ctx.refs.display.textContent = String(val)
})
})
</script>
В разметке пользовательский элемент
<my-counter>, внутри которого <span> и <button>. Разметка генерируется Astro на этапе сборки. Вместо Astro может быть любой генератор статики или серверное решение, которое отдаёт готовый HTML.Затем подключается nanotags. Функция
define() определяет пользовательский элемент. В withProps() указываются реактивные свойства, их тип и начальное значение. В withRefs() задаются ссылки на узлы, которые должны быть в разметке.В
setup() идёт установка обработчиков событий и эффектов, которые меняют значения реактивных свойств. Доступен объект контекста ctx, в котором хранятся свойства, ссылки на узлы и прочая информация о компоненте.Библиотека хорошо интегрирована с TypeScript, выводит типы, поддерживает Standard Schema валидаторы (Valibot, Zod, ArkType) для свойств, работает с данными в формате JSON, делает проверки в рантайме на основе схем.
Больше возможностей nanotags описано в документации. Это интересный взгляд на то, как работать с веб-компонентами. Миграция сэкономила 100кб JS, что хорошо и позволяет лучше вписываться в бюджеты производительности.
Также я обратил внимание, что библиотека разработана с уважением к стандарту HTML. Ссылки на элементы отмечаются атрибутом
data-ref, JSON-данные хранятся в блоках данных, пользовательские элементы названы в соответствии с правилами.Маленькая деталь, которая, тем не менее, отражает отношение автора к стандартам. Все синтаксические расширения выполнены в соответствии с правилами расширения HTML, без выдуманного синтаксиса с невалидной разметкой. За это от меня респект.
#js #tools
evilmartians.com
From React to native web with nanotags: a migration that saved 100 KB—Martian Chronicles, Evil Martians’ team blog
Most marketing sites ship a SPA framework just to toggle a sidebar. Here's how we migrated an Astro site from React and Ark UI to native Web Components: 100 KB less JavaScript, no functionality lost, and a tiny library called nanotags that makes Custom Elements…
🔥3🤔3❤2⚡1
Разработка сайтов, дружелюбных для агентов
ИИ агенты ворвались в нашу жизнь и стали ещё одними потребителями Интернета. В 525 выпуске Веб-стандартов обсуждали статью с web.dev о разработке сайтов, дружелюбных для агентов. Сейчас это набирает популярность.
Агенты взаимодействуют с сайтами одним из трёх способов:
- Анализ скриншота страницы с помощью машинного зрения;
- Анализ HTML-кода страницы и построенного на его основе DOM;
- Анализ дерева доступности, построенного из DOM и CSSOM.
Возможны комбинации этих способов, чтобы разрешить неоднозначные моменты: в разметке может быть кнопка «Добавить в корзину» как
В статье даются советы, которые помогут агентам лучше воспринимать сайт:
- Все действия чётко обозначены в интерфейсе;
- Структура сайта стабильная и консистентная;
- Нет прозрачных наложений поверх интерфейса;
- Структура контента передана с помощью семантического HTML или ARIA, если нет возможности использовать семантический HTML;
- Интерактивные элементы обозначены в CSS с помощью
- Поля формы и подписи к ним связаны через
- Размер интерактивных элементов как минимум 8×8px.
Глядя на эти пункты я понимаю: адаптация сайта для агентов — это просто создание нормального сайт для людей. Все советы были актуальны задолго до бума агентов. Это просто базовые советы как сделать хороший сайт.
Чётко идентифицируемые элементы, стабильная структура, семантический HTML, ARIA для нестандартных виджетов, связь полей с метками, размер элементов, курсор с пальцем и отсутствие наложений — это база при разработке сайтов.
Всё настолько плохо, что теперь это не база, а новая модная дисциплина и навык «адаптация сайта для агентов»? С другой стороны, если это подстегнёт внедрение хороших практик для улучшения сайтов, то почему бы и нет.
Тем, кто всегда стремился к качественным, семантичным, доступным и быстрым сайтам, выбирал готовый HTML и статику вместо SPA и сложных решений — повезло, их сайты уже со старта гораздо лучше адаптированы для агентов.
Стоит сказать, что в рамках Agentic Engine Optimization есть более специфические приёмы, как описывает Эдди Османи. Но они всё равно сводятся к предоставлению краткой выжимки контента, ссылкам и грамотной структуре.
Важно кратко и чётко донести смысл, контент должен быть структурирован с помощью списков и иерархии заголовков, должно быть содержание с кратким описанием и ссылками. То есть всё примерно так же, как и для людей.
#html #css #ui
ИИ агенты ворвались в нашу жизнь и стали ещё одними потребителями Интернета. В 525 выпуске Веб-стандартов обсуждали статью с web.dev о разработке сайтов, дружелюбных для агентов. Сейчас это набирает популярность.
Агенты взаимодействуют с сайтами одним из трёх способов:
- Анализ скриншота страницы с помощью машинного зрения;
- Анализ HTML-кода страницы и построенного на его основе DOM;
- Анализ дерева доступности, построенного из DOM и CSSOM.
Возможны комбинации этих способов, чтобы разрешить неоднозначные моменты: в разметке может быть кнопка «Добавить в корзину» как
<div>, но на скриншоте она будет выглядеть как кнопка, а JS добавит необходимое поведение (не делайте так).В статье даются советы, которые помогут агентам лучше воспринимать сайт:
- Все действия чётко обозначены в интерфейсе;
- Структура сайта стабильная и консистентная;
- Нет прозрачных наложений поверх интерфейса;
- Структура контента передана с помощью семантического HTML или ARIA, если нет возможности использовать семантический HTML;
- Интерактивные элементы обозначены в CSS с помощью
cursor: pointer;- Поля формы и подписи к ним связаны через
<label for="...">;- Размер интерактивных элементов как минимум 8×8px.
Глядя на эти пункты я понимаю: адаптация сайта для агентов — это просто создание нормального сайт для людей. Все советы были актуальны задолго до бума агентов. Это просто базовые советы как сделать хороший сайт.
Чётко идентифицируемые элементы, стабильная структура, семантический HTML, ARIA для нестандартных виджетов, связь полей с метками, размер элементов, курсор с пальцем и отсутствие наложений — это база при разработке сайтов.
Всё настолько плохо, что теперь это не база, а новая модная дисциплина и навык «адаптация сайта для агентов»? С другой стороны, если это подстегнёт внедрение хороших практик для улучшения сайтов, то почему бы и нет.
Тем, кто всегда стремился к качественным, семантичным, доступным и быстрым сайтам, выбирал готовый HTML и статику вместо SPA и сложных решений — повезло, их сайты уже со старта гораздо лучше адаптированы для агентов.
Стоит сказать, что в рамках Agentic Engine Optimization есть более специфические приёмы, как описывает Эдди Османи. Но они всё равно сводятся к предоставлению краткой выжимки контента, ссылкам и грамотной структуре.
Важно кратко и чётко донести смысл, контент должен быть структурирован с помощью списков и иерархии заголовков, должно быть содержание с кратким описанием и ссылками. То есть всё примерно так же, как и для людей.
#html #css #ui
❤8👍4😁1🤔1
15й Всемирный День Осведомлённости о Доступности
Сегодня, 21 мая 2026 — всемирный день осведомлённости о доступности (Global Accessibility Awareness Day — GAAD). Это отличный повод напомнить о важности доступности и поделиться материалами на эту тему.
Я регулярно пишу в канале разные посты на тему доступности в вебе и отмечаю эти посты тегом #a11y@alexnozer_dev. К сожалению, теги в канале появились не сразу, поэтому часть материалов о доступности не помечена.
В конце марта вышел ежегодный отчёт The WebAIM Million с результатами анализа доступности миллиона сайтов с помощью инструмента WAVE. Также данные о состоянии доступности можно найти в отчёте Web Almanac 2025 от HttpArchive.
По итогам WebAIM 2026 в топе проблем из года в год один и те же, только некоторые пункты меняются местами. В этом году список такой:
- Недостаточный уровень контрастности текста на 83.9% сайтов;
- Отсутствующий альтернативный текст у изображений на 53.1% сайтов;
- Отсутствующие подписи у полей ввода на 51% сайтов;
- Пустые ссылки на 46.3% сайтов;
- Пустые кнопки на 30.6% сайтов;
- Отсутствующий язык документа на 13.5% сайтов.
Это лишь автоматически обнаруживаемые проблемы. Часть проблем не может быть обнаружена автоматическими средствами анализа. По каждой проблеме из топа планирую сделать отдельный пост, их не сложно исправить.
Есть папки с телеграм-каналами о доступности, собранные Верой Шингарёвой:
- Accessibility-папка — каналы, которые пишут про доступность или около;
- a11y_person — блоги людей с инвалидностью и без, которые пишут про доступность, инклюзию свою жизнь;
- a11y_org — организации в сфере доступности и инклюзии.
У Стаса Мельникова есть интересная серия статей про HTML и CSS ошибки, которые влияют на доступность (вся серия доступна по тегу #html_css_a11y_story_melnik909). Стас вместе со своим знакомым Ильёй, незрячим человеком, делятся распространёнными ошибками и как их исправить.
#a11y
Сегодня, 21 мая 2026 — всемирный день осведомлённости о доступности (Global Accessibility Awareness Day — GAAD). Это отличный повод напомнить о важности доступности и поделиться материалами на эту тему.
Я регулярно пишу в канале разные посты на тему доступности в вебе и отмечаю эти посты тегом #a11y@alexnozer_dev. К сожалению, теги в канале появились не сразу, поэтому часть материалов о доступности не помечена.
В конце марта вышел ежегодный отчёт The WebAIM Million с результатами анализа доступности миллиона сайтов с помощью инструмента WAVE. Также данные о состоянии доступности можно найти в отчёте Web Almanac 2025 от HttpArchive.
По итогам WebAIM 2026 в топе проблем из года в год один и те же, только некоторые пункты меняются местами. В этом году список такой:
- Недостаточный уровень контрастности текста на 83.9% сайтов;
- Отсутствующий альтернативный текст у изображений на 53.1% сайтов;
- Отсутствующие подписи у полей ввода на 51% сайтов;
- Пустые ссылки на 46.3% сайтов;
- Пустые кнопки на 30.6% сайтов;
- Отсутствующий язык документа на 13.5% сайтов.
Это лишь автоматически обнаруживаемые проблемы. Часть проблем не может быть обнаружена автоматическими средствами анализа. По каждой проблеме из топа планирую сделать отдельный пост, их не сложно исправить.
Есть папки с телеграм-каналами о доступности, собранные Верой Шингарёвой:
- Accessibility-папка — каналы, которые пишут про доступность или около;
- a11y_person — блоги людей с инвалидностью и без, которые пишут про доступность, инклюзию свою жизнь;
- a11y_org — организации в сфере доступности и инклюзии.
У Стаса Мельникова есть интересная серия статей про HTML и CSS ошибки, которые влияют на доступность (вся серия доступна по тегу #html_css_a11y_story_melnik909). Стас вместе со своим знакомым Ильёй, незрячим человеком, делятся распространёнными ошибками и как их исправить.
#a11y
1🔥4❤2🥰1🎉1
Недостаточный уровень контрастности текста
Контрастность определяет соотношение между цветом текста и цветом фона, что влияет на читаемость, утомляемость глаз и способность визуального восприятия контента людьми с нарушениями зрения. Это самая частая проблема доступности по данным WebAIM.
Существует два алгоритма измерения контрастности: WCAG и APCA. Первый существует с момента появления стандарта WCAG и используется во всех текущих версиях стандарта, но даёт ложно-позитивные результаты для некоторых сочетаний цветов.
APCA более новый и надёжный алгоритм. Он учитывает восприятие человеческого глаза, поэтому более точно отражает контрастность. APCA заменит текущий алгоритм в стандарте WCAG 3, а пока массовым остаётся старый алгоритм WCAG.
Есть 3 критерия WCAG, которые затрагивают контрастность:
- 1.4.3 Contrast (Minimum);
- 1.4.6 Contrast (Enhanced);
- 1.4.11 Non-text Contrast.
Я сосредоточусь на 1.4.3. Потому что 1.4.6 выдвигает повышенные требования и исходит из того, что 1.4.3 удовлетворён. А 1.4.11 рассматривает нетекстовый контент, там иные требования и эта проблема не входит в топ самых распространённых.
Критерий 1.4.3 выдвигает следующие требования к уровню контрастности текста:
- 4.5:1 для текста размером до 24px или полужирного текста размером до 19px;
- 3:1 для текста размером от 24px или полужирного текста размером от 19px.
Проблема со стороны разработчиков, которые задают цвета в CSS, в том, что они получают от дизайнеров готовые макеты. Какие цветам там есть, такие переносятся в код. То есть контрастность текста — зона ответственности дизайнеров.
Поэтому исправление проблемы стоит начать с дизайна: установить требования и добавить в чеклист проверки. Инициатива может исходить и от разработки на этапе передачи макета в виде комментариев о недостаточной контрастности.
Для проверки контрастности текста в Figma есть плагины. Я пользуюсь плагином Contrast, но есть много других. Также рекомендую Polychrome, хоть он и работает по алгоритму APCA, он точнее отражает реальный уровень контрастности.
Если продукт большой, над ним работают несколько команд и есть дизайн-система, то проблему контрастности стоит решать на уровне дизайн-системы. Проверить палитру, гайды по использованию цветов, модули типографики.
А если это маленький проект, дизайнер сдал макет, получил оплату и ушёл? Частое явление в заказной разработке сайтов. Тут я предлагаю брать ситуацию в свои руки и отходить от цветов в макете ради пользователей. То есть исправлять неконтрастные цвета.
Процесс такой: сверстайте с цветами из макета, откройте в Chrome Dev Tools вкладку CSS Overview и запустите тест. Он покажет все используемые на странице цвета и уровни контрастности. Затем можно исправить цвет в палитре выбора и перенести в код.
А если дизайнер всё же вернётся и что-то скажет? Ну, это упущение дизайнера, его ответственность. А если заказчик скажет? Тут сложнее, но можно объяснять это как умышленную правку ради UX. Но обычно цвет не сильно меняется.
Есть другая проблема — текст на фоне изображений. Проблема в том, что фото или что-то сложное состоит из огромного количества цветов. Из-за многообразия экранов, невозможно предсказать поверх какой части будет находиться текст.
WCAG на этот счёт говорит, что нужно осуществить проверку контрастности с каждым цветом той части изображения, поверх которой находится текст. Это сложно и многие инструменты такое проверять не умеют.
Если у сайта ко всему прочему есть CMS, то одно изображение может быть заменено на другое и контент-менеджер проверять контрастность в сотне точек точно не будет. Лучше вообще избегать наложения текста поверх изображений.
Но если очень хочется, то простой совет — добавьте одноцветную подложку для текста. Вариант два: затемните место наложения текста через градиент. Вариант три: добавьте эффект «гало» тексту через тень. Но лучше всего подложка.
#a11y
Контрастность определяет соотношение между цветом текста и цветом фона, что влияет на читаемость, утомляемость глаз и способность визуального восприятия контента людьми с нарушениями зрения. Это самая частая проблема доступности по данным WebAIM.
Существует два алгоритма измерения контрастности: WCAG и APCA. Первый существует с момента появления стандарта WCAG и используется во всех текущих версиях стандарта, но даёт ложно-позитивные результаты для некоторых сочетаний цветов.
APCA более новый и надёжный алгоритм. Он учитывает восприятие человеческого глаза, поэтому более точно отражает контрастность. APCA заменит текущий алгоритм в стандарте WCAG 3, а пока массовым остаётся старый алгоритм WCAG.
Есть 3 критерия WCAG, которые затрагивают контрастность:
- 1.4.3 Contrast (Minimum);
- 1.4.6 Contrast (Enhanced);
- 1.4.11 Non-text Contrast.
Я сосредоточусь на 1.4.3. Потому что 1.4.6 выдвигает повышенные требования и исходит из того, что 1.4.3 удовлетворён. А 1.4.11 рассматривает нетекстовый контент, там иные требования и эта проблема не входит в топ самых распространённых.
Критерий 1.4.3 выдвигает следующие требования к уровню контрастности текста:
- 4.5:1 для текста размером до 24px или полужирного текста размером до 19px;
- 3:1 для текста размером от 24px или полужирного текста размером от 19px.
Проблема со стороны разработчиков, которые задают цвета в CSS, в том, что они получают от дизайнеров готовые макеты. Какие цветам там есть, такие переносятся в код. То есть контрастность текста — зона ответственности дизайнеров.
Поэтому исправление проблемы стоит начать с дизайна: установить требования и добавить в чеклист проверки. Инициатива может исходить и от разработки на этапе передачи макета в виде комментариев о недостаточной контрастности.
Для проверки контрастности текста в Figma есть плагины. Я пользуюсь плагином Contrast, но есть много других. Также рекомендую Polychrome, хоть он и работает по алгоритму APCA, он точнее отражает реальный уровень контрастности.
Если продукт большой, над ним работают несколько команд и есть дизайн-система, то проблему контрастности стоит решать на уровне дизайн-системы. Проверить палитру, гайды по использованию цветов, модули типографики.
А если это маленький проект, дизайнер сдал макет, получил оплату и ушёл? Частое явление в заказной разработке сайтов. Тут я предлагаю брать ситуацию в свои руки и отходить от цветов в макете ради пользователей. То есть исправлять неконтрастные цвета.
Процесс такой: сверстайте с цветами из макета, откройте в Chrome Dev Tools вкладку CSS Overview и запустите тест. Он покажет все используемые на странице цвета и уровни контрастности. Затем можно исправить цвет в палитре выбора и перенести в код.
А если дизайнер всё же вернётся и что-то скажет? Ну, это упущение дизайнера, его ответственность. А если заказчик скажет? Тут сложнее, но можно объяснять это как умышленную правку ради UX. Но обычно цвет не сильно меняется.
Есть другая проблема — текст на фоне изображений. Проблема в том, что фото или что-то сложное состоит из огромного количества цветов. Из-за многообразия экранов, невозможно предсказать поверх какой части будет находиться текст.
WCAG на этот счёт говорит, что нужно осуществить проверку контрастности с каждым цветом той части изображения, поверх которой находится текст. Это сложно и многие инструменты такое проверять не умеют.
Если у сайта ко всему прочему есть CMS, то одно изображение может быть заменено на другое и контент-менеджер проверять контрастность в сотне точек точно не будет. Лучше вообще избегать наложения текста поверх изображений.
Но если очень хочется, то простой совет — добавьте одноцветную подложку для текста. Вариант два: затемните место наложения текста через градиент. Вариант три: добавьте эффект «гало» тексту через тень. Но лучше всего подложка.
#a11y
👍8❤3🔥1🤔1🌚1
Решение проблемы с уровнями заголовков
Есть одна давняя и нерешённая проблема: неверная иерархия заголовков. А именно пропущенные уровни заголовков, когда за
С компонентным подходом может быть трудно учесть контекст. Страница с
В таком сценарии структура будет верной:
Если использовать тот же компонент «список товаров» на странице каталога, где в
Проблему пытаются решить уже давно. На канале есть пост про структуру заголовков и outline, где попытки подробно описаны. Если кратко, то много лет пытались, не смогли, удалили алгоритм из стандарта и отказались от реализации.
Тут на днях Джейк Арчибальд рассказал, что в Firefox экспериментируют с решением проблемы пропуска уровней заголовков. То есть вновь предпринимается попытка решить проблему. И решение планируют стандартизировать.
Предлагается новый глобальный атрибут
В комментариях подтвердили, что это также работает с элементами
Может возникнуть вопрос: а что будет с
Заголовки иногда стилизуют по селектору элемента, который привязывает стили к уровню в названии элемента. Как тогда стилизовать заголовки по уровнями, если все они
Реализация появится в Firefox Nightly 153 за флагом экспериментальных технологий. С одной стороны крутая функция, с другой это возврат к использованию
#html #a11y
Есть одна давняя и нерешённая проблема: неверная иерархия заголовков. А именно пропущенные уровни заголовков, когда за
<h1> следует <h3>. Ухудшается структура страницы и навигация с помощью вспомогательных технологий.С компонентным подходом может быть трудно учесть контекст. Страница с
<h1> рисует компонент «популярные товары» с заголовком <h2>, а он рисует компонент «список товаров» с карточками, у каждой из которых заголовок <h3>.// Код для иллюстрации
function HomePage() {
return `
<main>
<h1>Магазин</h1>
${BestSellers()}
</main>
`;
}
function BestSellers() {
return `
<section>
<h2>Популярные товары</h2>
${ProductList()}
</section>
`;
}
function ProductList() {
return `
<ul>
${products.map(product => `
<li>
<article>
<h3>${product.title}</h3>
</article>
</li>
`).join('')}
</ul>
`;
}
document.body.innerHTML += HomePage();
В таком сценарии структура будет верной:
Магазин
└── Популярные товары
├── Товар 1
├── Товар 2
└── ...
Если использовать тот же компонент «список товаров» на странице каталога, где в
<h1> обычно название категории, а дальше идёт сетка с карточками товаров, то получится пропуск заголовка <h2>. Карточки не учитывают контекст.function CollectionPage() {
return `
<main>
<h1>Холодильники</h1>
${ProductList()}
</main>
`;
}
function ProductList() {
// как в предыдущем примере
}
document.body.innerHTML += CollectionPage();Проблему пытаются решить уже давно. На канале есть пост про структуру заголовков и outline, где попытки подробно описаны. Если кратко, то много лет пытались, не смогли, удалили алгоритм из стандарта и отказались от реализации.
Тут на днях Джейк Арчибальд рассказал, что в Firefox экспериментируют с решением проблемы пропуска уровней заголовков. То есть вновь предпринимается попытка решить проблему. И решение планируют стандартизировать.
Дисклеймер: это обзор раннего предложения новых функций. Синтаксис может измениться в будущем или от функций могут отказаться
Предлагается новый глобальный атрибут
headingoffset. Он задаёт смещение уровня для всех вложенных заголовков. С этим вновь предлагается использовать для заголовков только <h1> и его уровень будет вычисляться на основе смещения.<main>
<h1>Магазин</h1>
<!--
задано смещение
уровня заголовков
-->
<section headingoffset="1">
<!-- тут будет уровень 2 -->
<h1>Популярные товары</h1>
<!--
задано смещение
уровня заголовков
-->
<ul headingoffset="1">
<li>
<article>
<!-- тут будет уровень 3 -->
<h1>Товар 1</h1>
</article>
</li>
<li>
<article>
<!-- тут будет уровень 3 -->
<h1>Товар 1</h1>
</article>
</li>
...
</ul>
</section>
</main>
В комментариях подтвердили, что это также работает с элементами
<h2>-<h6>. Если задано смещение, то уровень заголовка меняется на совокупное смещение. При смещении в 1 уровень <h2> становится <h3> и так далее.Может возникнуть вопрос: а что будет с
<h6>? На это также дали ответ: он станет <h7> и так вплоть до 9 уровня максимум. В HTML нет <h7>, но с помощью атрибута aria-level="7" заголовку можно задать более глубокий уровень.Заголовки иногда стилизуют по селектору элемента, который привязывает стили к уровню в названии элемента. Как тогда стилизовать заголовки по уровнями, если все они
<h1>? Об этом тоже подумали и добавили селектор :heading()::heading(2) {
/*
Выберет все заголовки у которых
вычисленный уровень 2
*/
}Реализация появится в Firefox Nightly 153 за флагом экспериментальных технологий. С одной стороны крутая функция, с другой это возврат к использованию
<h1> для всех заголовков, что сломает текущие инструменты анализа дерева заголовков.#html #a11y
Bluesky Social
Firefox for Web Developers (@webdevs.firefox.com)
Ever struggled to get heading tags right in includes/components? headingoffset could be the answer…
👍7❤4😱4👨💻1
Спецификация для сайтов
Йост де Валк, известный по плагину Yoast SEO для WordPress, создал спецификацию для сайтов — набор правил, руководств и чеклистов для проверки качества сайтов. Спецификация адаптирована для агентов, отдаёт страницы в .md, есть MCP.
Спецификация охватывает базовые вещи, SEO, доступность, безопасность, Well-Known URL, доступ агентов, производительность, приватность, устойчивость и интернационализацию. Всего 128 пунктов на данный момент.
Я, как человек небезразличный к качеству сайтов, сам хотел создать похожий ресурс и начал с чеклиста. Спецификация идёт дальше и не просто говорит, как должно быть, а описывает причины, реализацию и проверки, даёт дополнительные ссылки.
Спецификация для сайтов — хороший и современный источник хороших практик. Рекомендую взять на вооружение, если вы хотите создать качественный сайт. Вот бы ещё появился инструмент автоматического анализа этого всего…
#tools
Йост де Валк, известный по плагину Yoast SEO для WordPress, создал спецификацию для сайтов — набор правил, руководств и чеклистов для проверки качества сайтов. Спецификация адаптирована для агентов, отдаёт страницы в .md, есть MCP.
Спецификация охватывает базовые вещи, SEO, доступность, безопасность, Well-Known URL, доступ агентов, производительность, приватность, устойчивость и интернационализацию. Всего 128 пунктов на данный момент.
Я, как человек небезразличный к качеству сайтов, сам хотел создать похожий ресурс и начал с чеклиста. Спецификация идёт дальше и не просто говорит, как должно быть, а описывает причины, реализацию и проверки, даёт дополнительные ссылки.
Спецификация для сайтов — хороший и современный источник хороших практик. Рекомендую взять на вооружение, если вы хотите создать качественный сайт. Вот бы ещё появился инструмент автоматического анализа этого всего…
#tools
The Website Specification
A platform-agnostic, full specification of the technical features a good website should have. Built in the open under an MIT licence.
🔥9👍2❤1❤🔥1
Слоты без Shadow DOM
В HTML есть элемент
Цель атрибута
Я тут подумал: а если использовать атрибут
Сейчас объясню что тут происходит. Внутри
Функция
Если в
Функция
В свойстве
Это работает в браузерах с поддержкой расширенной функции
Это решение можно слегка деградировать, отказавшись от
Я использую пользовательский элемент
Так на HTML и CSS можно создавать компоненты с некоторым API «слотов». И использование для этого существующего атрибута
#css
В HTML есть элемент
<slot> и атрибут с таким же названием — slot. Работают они только с Shadow DOM. Цель элемента <slot> — обозначить стандартную или именованную ячейку для перемещения элементов из DOM в Shadow DOM.Цель атрибута
slot — указать имя ячейки, которую создаёт <slot name="…">, куда должен попасть элемент. Там ещё хитрые правила проникновения стилей в Shadow DOM и селекторы :slotted() и :has-slotted. Но это всё про Shadow DOM.Я тут подумал: а если использовать атрибут
slot без Shadow DOM? Так он не работает, но современный CSS на многое способен. Можно создать grid с именованными ячейками и распределить по ним элементы с помощью attr() и grid-area.input-wrapper {
display: inline-grid;
grid-template-areas:
'label label label'
'before input after'
'info info info'
;
> :not([slot]) {
display: none !important;
}
> [slot] {
--slot: attr(
slot
type(label | before | input | after | info),
invalid
);
display: if(
style(--slot: invalid): none !important;
else: revert;
);
grid-area: if(
style(--slot: invalid): auto;
else: var(--slot);
);
}
}<input-wrapper>
<label
for="pwd"
slot="label"
>
Пароль
</label>
<input
type="password"
id="pwd"
autocomplete="new-password"
slot="input"
>
<button
type="button"
commandfor="pwd"
command="--toggle-password"
slot="after"
aria-pressed="false"
>
<!-- ... -->
</button>
<p slot="info">
Пароль должен содержать...
</p>
</input-wrapper>
Сейчас объясню что тут происходит. Внутри
input-wrapper объявлена сетка из трёх колонок с именованными ячейками label, before, input, after и info. Прямые потомки без атрибута slot скрываются, потому что он нужен.Функция
attr() считывает значение из атрибута slot и приводит его к заданному типу. Функция type() определяет CSS-тип значения, который представлен в виде перечисления доступных имён ячеек (как Union Type в Typescript).Если в
slot указано неподдерживаемое значение, то его не получится привести к типу, указанному в type(). В таком случае используется значение по умолчанию invalid. Результат attr() записывается в пользовательское свойство --slot.Функция
if() в свойстве display проверяет значение свойства --slot. Если там invalid, то есть в атрибуте задано неподдерживаемое имя ячейки, то такой элемент скрывается. Иначе revert возвращает заданное ранее значение.В свойстве
grid-area функция if() так же проверяет свойство --slot. При invalid устанавливается значение auto, но это не важно, потому что элемент будет скрыт. А если там допустимое значение, то элемент попадает в нужную ячейку.Это работает в браузерах с поддержкой расширенной функции
attr() и if(). Элементы можно менять местами и они всё равно попадут в нужные ячейки сетки. Ячейки могут быть пустыми, в примере нет элемента для слота before.Это решение можно слегка деградировать, отказавшись от
if() и attr() . Кода будет больше, но браузерная поддержка расширится и применить можно будет уже сейчас. Допустимые значения атрибута и ячейки нужно задать вручную.input-wrapper {
/* ... */
> :is(
:not([slot]),
[slot]:not(
[slot="label"],
[slot="before"],
...
)
)
{
display: none !important;
}
> [slot="label"] {
grid-area: label;
}
> [slot="before"] {
grid-area: before;
}
...
}Я использую пользовательский элемент
<input-wrapper> как обёртку, без JS. Удобно и логично, что имя контейнера намекает на суть. Можно использовать <div class="input-wrapper">, если так удобнее и привычнее.Так на HTML и CSS можно создавать компоненты с некоторым API «слотов». И использование для этого существующего атрибута
slot выглядит логично, хотя и не по назначению. Можно в случае чего заменить на data-slot.#css
🔥4🤯4❤1😱1🗿1
Forwarded from enable design - о дизайне и доступности (Анжелика Герман)
AI и доступность
Делаем блиц-интервью про AI и доступность. Задаем одинаковые вопросы и получаем разные ответы ) Наш третий гость — Алексей Назаренко @alexnozer_dev — фронтенд-разработчик, специализирующийся на вёрстке, доступности, производительности и веб-стандартах. Леша, спасибо 💜
Ты пробовал использовать Claude или ChatGPT со скринридером или с клавиатуры? Как это работает на практике?
— Лично я не пробовал. Но читал о том, что в интерфейсах таких платформ полно проблем с доступностью.
Ты знаешь кейсы, где AI улучшил доступность продукта?
— Есть несколько фич, которые кажутся мне хорошим использованием AI в доступности:
- Автогенерация субтитров на видео в TikTok, YouTube и подобных сервисах;
- Возможность сгенерировать описание изображения (alt) в Firefox или Shopify;
- Функция распознавания изображения с камеры в реальном времени в ChatGPT или Seeing AI;
Ещё знаю, что AI используют при аудите для анализа контента и поиска нарушений WCAG. Но пока о каких-то серъёзных успеха в этом направлении не слышал.
Есть ли риск, что AI-инструменты для доступности обучены на данных, которые не отражают реальный опыт людей с ограничениями по здоровью? Что должно измениться в том, как мы обучаем модели?
— Все современные модели знают о доступности много, потому что это гигантские базы знаний. Сложность в том, чтобы эти знания оттуда извлечь. По умолчанию модели выдают статистически наиболее вероятный код. Дела с доступностью обстоят плохо, что подтверждают отчёты WebAIM. Поэтому в среднем сгенерированный код будет содержать проблемы доступности.
С обучением моделей, скорее всего, уже ничего не сделать. Разве что в мире резко большинство сайтов и сервисов станут доступными и появятся новые хорошие кодовые базы, где это всё учтено. Но такого не будет. А учитывая волну нового сгенерированного кода за последние годы, всё только хуже.
Поэтому нужно обкладывать агентов скиллами, правилами, инструкциями для работы, давать примеры доступного кода, проводить код ревью людьми, которые разбираются. ИИ волшебным образом не сделает мир доступнее, нужна инициатива и эксперты.
70% новых приложений создаётся на low-code и no-code платформах. Люди без технической базы делают продукты для миллионов. AI научит их паттернам доступности?
— Я не слышал, чтобы без технической базы с помощью AI создавали продукты на миллионы пользователей. Истории «я за два вечера навайбкодил SaaS и заработал много денег» мне кажутся пылью в глаза. Десятки, сотни или тысячи пользователей, но не миллионы. Если говорить о крупных корпорациях, которые массово внедряют AI в процессы разработки, то там, всё же, есть техническая база.
Не думаю, что AI научит доступности. Он способен воспроизводить шаблоны доступности и выдавать неплохие решения при должной настройке и в руках опытных разработчиков. Тех, кто росто генерирует код и не вникает в него, AI ничему не научит.
В России активно пользуются технологиями с Ai — зарубежные скринридеры, программы по типу Open your eyes, есть ли надежда, что подобные сервисы будут разрабатываться российскими разработчиками?
— Думаю, что надежда есть. Однако стимулов меньше, чем в странах Евросоюза или США. Нужно развивать культуру доступности и работать над законодательной базой, по аналогии с ADA или EAA. Культура будет способствовать информационной осведомлённости о важности доступности, а законы обяжут выделять на это ресурсы.
Делаем блиц-интервью про AI и доступность. Задаем одинаковые вопросы и получаем разные ответы ) Наш третий гость — Алексей Назаренко @alexnozer_dev — фронтенд-разработчик, специализирующийся на вёрстке, доступности, производительности и веб-стандартах. Леша, спасибо 💜
Ты пробовал использовать Claude или ChatGPT со скринридером или с клавиатуры? Как это работает на практике?
— Лично я не пробовал. Но читал о том, что в интерфейсах таких платформ полно проблем с доступностью.
Ты знаешь кейсы, где AI улучшил доступность продукта?
— Есть несколько фич, которые кажутся мне хорошим использованием AI в доступности:
- Автогенерация субтитров на видео в TikTok, YouTube и подобных сервисах;
- Возможность сгенерировать описание изображения (alt) в Firefox или Shopify;
- Функция распознавания изображения с камеры в реальном времени в ChatGPT или Seeing AI;
Ещё знаю, что AI используют при аудите для анализа контента и поиска нарушений WCAG. Но пока о каких-то серъёзных успеха в этом направлении не слышал.
Есть ли риск, что AI-инструменты для доступности обучены на данных, которые не отражают реальный опыт людей с ограничениями по здоровью? Что должно измениться в том, как мы обучаем модели?
— Все современные модели знают о доступности много, потому что это гигантские базы знаний. Сложность в том, чтобы эти знания оттуда извлечь. По умолчанию модели выдают статистически наиболее вероятный код. Дела с доступностью обстоят плохо, что подтверждают отчёты WebAIM. Поэтому в среднем сгенерированный код будет содержать проблемы доступности.
С обучением моделей, скорее всего, уже ничего не сделать. Разве что в мире резко большинство сайтов и сервисов станут доступными и появятся новые хорошие кодовые базы, где это всё учтено. Но такого не будет. А учитывая волну нового сгенерированного кода за последние годы, всё только хуже.
Поэтому нужно обкладывать агентов скиллами, правилами, инструкциями для работы, давать примеры доступного кода, проводить код ревью людьми, которые разбираются. ИИ волшебным образом не сделает мир доступнее, нужна инициатива и эксперты.
70% новых приложений создаётся на low-code и no-code платформах. Люди без технической базы делают продукты для миллионов. AI научит их паттернам доступности?
— Я не слышал, чтобы без технической базы с помощью AI создавали продукты на миллионы пользователей. Истории «я за два вечера навайбкодил SaaS и заработал много денег» мне кажутся пылью в глаза. Десятки, сотни или тысячи пользователей, но не миллионы. Если говорить о крупных корпорациях, которые массово внедряют AI в процессы разработки, то там, всё же, есть техническая база.
Не думаю, что AI научит доступности. Он способен воспроизводить шаблоны доступности и выдавать неплохие решения при должной настройке и в руках опытных разработчиков. Тех, кто росто генерирует код и не вникает в него, AI ничему не научит.
В России активно пользуются технологиями с Ai — зарубежные скринридеры, программы по типу Open your eyes, есть ли надежда, что подобные сервисы будут разрабатываться российскими разработчиками?
— Думаю, что надежда есть. Однако стимулов меньше, чем в странах Евросоюза или США. Нужно развивать культуру доступности и работать над законодательной базой, по аналогии с ADA или EAA. Культура будет способствовать информационной осведомлённости о важности доступности, а законы обяжут выделять на это ресурсы.
👍6❤2🥰1
Фреймворки не нужны?
Недавно видел фрагмент со стрима Тимура Шемсединова, затем реакцию на этот фрагмент автора канала «Фронтенд как проблема». Тимур высказал мнение: «в современном мире фронтенд фреймворки не нужны, это инерция».
Громкое заявление, но основано на том, что в современных браузерах появилось много API, с помощью которых можно создавать приложения без фреймворков. А массовое использование фреймворков — это инерция и сила умолчания.
Также речь идёт о паразитной сложности. С одной стороны, фреймворки созданы для уменьшения сложности. Они прячут от нас готовые реализации сложных концепции. На разработку этого с нуля приходилось бы тратить много ресурсов.
С другой стороны, необходимы знания фреймворка, иногда специфические (хуки, мемоизация и борьба с ререндерами в React). С фреймворком приходят тысячи зависимостей. Нужно их проверять, обновлять, защищаться от атак.
Кроме того, фреймворки соревнуются между собой за внимание разработчиков. Они стараются быть как можно более универсальными, решать широкий спектр задач. Но это влечёт за собой больше и больше абстракций.
Можно выбрать Vue и использовать только 20% возможностей. Остальные 80% живут в кодовой базе (node_modules), скачиваются, обновляются, проходят процесс сборки (анализ графа зависимостей, Tree Shaking, удаление неиспользуемого кода).
Мало кто об этом задумывается, потому что это вопросы инфраструктуры. Всё это имеет свою цену. Паразитная сложность — цена удобства абстракций. И в этом, как мне кажется, основной посыл Тимура против фреймворков.
«Если не используется фреймворк, то будет написан свой». Абстракции всё равно будут написаны, это неизбежно. Но это свои, полностью контролируемые абстракции, решающие только нужную задачу, а не гипотетические задачи кого-то ещё.
Современные браузерные API забирают на себя часть функциональности. Многое можно перенести с клиента на сервер, сняв с браузера ответственность за роутинг, загрузку и хранение данных, управление состоянием и так далее.
Ну и золотое правило, о котором говорят, но которое забывают: для каждой задачи есть свой инструмент. Если проект не сложный, то нужны соответствующие инструменты. Многие проекты не такие сложные, какими кажутся.
Поэтому идея Тимура хоть и громко звучит, но точно не лишена смысла. Я писал про доклад «отказаться от зависимостей и не умереть» и делился сайтом Plain Vanilla, которые показывают, что это возможно, хотя и непривычно.
#js
Недавно видел фрагмент со стрима Тимура Шемсединова, затем реакцию на этот фрагмент автора канала «Фронтенд как проблема». Тимур высказал мнение: «в современном мире фронтенд фреймворки не нужны, это инерция».
Громкое заявление, но основано на том, что в современных браузерах появилось много API, с помощью которых можно создавать приложения без фреймворков. А массовое использование фреймворков — это инерция и сила умолчания.
Также речь идёт о паразитной сложности. С одной стороны, фреймворки созданы для уменьшения сложности. Они прячут от нас готовые реализации сложных концепции. На разработку этого с нуля приходилось бы тратить много ресурсов.
С другой стороны, необходимы знания фреймворка, иногда специфические (хуки, мемоизация и борьба с ререндерами в React). С фреймворком приходят тысячи зависимостей. Нужно их проверять, обновлять, защищаться от атак.
Кроме того, фреймворки соревнуются между собой за внимание разработчиков. Они стараются быть как можно более универсальными, решать широкий спектр задач. Но это влечёт за собой больше и больше абстракций.
Можно выбрать Vue и использовать только 20% возможностей. Остальные 80% живут в кодовой базе (node_modules), скачиваются, обновляются, проходят процесс сборки (анализ графа зависимостей, Tree Shaking, удаление неиспользуемого кода).
Мало кто об этом задумывается, потому что это вопросы инфраструктуры. Всё это имеет свою цену. Паразитная сложность — цена удобства абстракций. И в этом, как мне кажется, основной посыл Тимура против фреймворков.
«Если не используется фреймворк, то будет написан свой». Абстракции всё равно будут написаны, это неизбежно. Но это свои, полностью контролируемые абстракции, решающие только нужную задачу, а не гипотетические задачи кого-то ещё.
Современные браузерные API забирают на себя часть функциональности. Многое можно перенести с клиента на сервер, сняв с браузера ответственность за роутинг, загрузку и хранение данных, управление состоянием и так далее.
Ну и золотое правило, о котором говорят, но которое забывают: для каждой задачи есть свой инструмент. Если проект не сложный, то нужны соответствующие инструменты. Многие проекты не такие сложные, какими кажутся.
Поэтому идея Тимура хоть и громко звучит, но точно не лишена смысла. Я писал про доклад «отказаться от зависимостей и не умереть» и делился сайтом Plain Vanilla, которые показывают, что это возможно, хотя и непривычно.
#js
👍14❤4🔥1😎1
Вредные компоненты без JS
Мне нравится идея создания компонентов без JS. Видео Native CSS Components vs Modern UI Libraries показывает реализацию нескольких компонентов на HTML/CSS и сравнивает их с аналогами из Shadcn.
Компоненты в Shadcn действительно переусложнены. Но у показанных в видео аналогов есть проблемы. Рассмотрим, что не так с каждой реализацией и как можно сделать лучше (сейчас или в будущем).
Диалог
Диалог реализован с помощью Popover API.
Есть
Выпадающее меню
В видео выпадающее меню реализовано с помощью
Виджет
Всплывающая подсказка
В видео отображение подсказки реализовано через
Реализация поведения для соответствия 1.4.13 требует JS. Можно использовать
Вкладки
Вкладки реализованы как набор радио-кнопок, которые в сочетании с псевдо-классом
На канале есть разбор вкладок с использованием ссылок
Аккордеон
На последок виджет аккордеона. В видео он сделан из нескольких
Вот аккордеон можно использовать вместо решений на JS, это не хак. Тут ещё можно углубиться в различия аккордеона и раскрываемых панелей, но в другой раз. А примеры диалога, меню, подсказки и вкладок из видео использовать не стоит.
#html #css #js #ui
Мне нравится идея создания компонентов без JS. Видео Native CSS Components vs Modern UI Libraries показывает реализацию нескольких компонентов на HTML/CSS и сравнивает их с аналогами из Shadcn.
Компоненты в Shadcn действительно переусложнены. Но у показанных в видео аналогов есть проблемы. Рассмотрим, что не так с каждой реализацией и как можно сделать лучше (сейчас или в будущем).
Диалог
Диалог реализован с помощью Popover API.
popover не задаёт нужную семантику. <div popover> остаётся контейнером с role="group". У диалога должна быть соответствующая семантика, состояния, поведение и UX.Есть
<dialog>, который обладает нужной семантикой и свойствами. Он работает с popover для немодальных диалогов, а с command для модальных и немодальных. Атрибут closedby="any" добавляет закрытие по нажатию вне диалога.<!-- немодальный диалог с popover -->
<button
popovertarget="dlg"
popovertargetaction="show"
>
Open dialog
</button>
<dialog id="dlg" popover>
...
<button
popovertarget="dlg"
popovertargetaction="hide"
>
Close
</button>
</dialog>
<!-- немодальный диалог с command -->
<button
commandfor="dlg"
command="show-popover"
>
Open dialog
</button>
<dialog id="dlg" popover>
...
<button
commandfor="dlg"
command="hide-popover"
>
Close
</button>
</dialog>
<!-- модальный диалог с command и closedby -->
<button
commandfor="dlg"
command="show-modal"
>
Open dialog
</button>
<dialog id="dlg" closedby="any">
...
<button
commandfor="dlg"
command="close"
>
Close
</button>
</dialog>
Выпадающее меню
В видео выпадающее меню реализовано с помощью
popover и Anchor Positioning. Как и с диалогом, меню не обладает нужной семантикой и поведением. Dropdown menu в Shadcn реализован как элемент с ролью menu.Виджет
menu предназначен для команд, а не навигационных ссылок. Внутри допустимы только определённые роли. Требуется навигация стрелками и Home/End. Для этого нужен JS. Всё может измениться с приходом focusgroup, но пока это экспериментальный API.<button
commandfor="menu"
command="toggle-popover"
>
Open menu
</button>
<div
id="menu"
role="menu"
popover
focusgroup="menu"
>
<button role="menuitem">
Profile
</button>
<button role="menuitem">
Settings
</button>
<button role="menuitem">
Sign out
</button>
</div>
Всплывающая подсказка
В видео отображение подсказки реализовано через
:hover/:focus и комбинатор ~. Роль подсказки — tooltip, а кнопка ссылается на неё через aria-describedby. Такая всплывающая подсказка нарушает критерий WCAG 1.4.13 Content on Hover or Focus. Реализация поведения для соответствия 1.4.13 требует JS. Можно использовать
popover с его закрытием по Esc, но отображение потребует JS. Interest Invokers API и popover="hint" позволят в будущем реализовать это без JS.<button
interestfor="copy"
aria-describedby="copy"
>
Copy
</button>
<span
id="copy"
popover="hint"
role="tooltip"
>
Hover or focus me
</span>
Вкладки
Вкладки реализованы как набор радио-кнопок, которые в сочетании с псевдо-классом
:checked и селектором :has() у родителя переключают дочерние панели. Вновь не хватает нужной семантики и поведения и в целом это хак.На канале есть разбор вкладок с использованием ссылок
<a> и псевдо-класса :target и почему это не вкладки. То же с радио-кнопоками и :has(). Реализовать вкладки без JS сейчас нельзя, но, возможно, появятся новые элементы или примитивы.Аккордеон
На последок виджет аккордеона. В видео он сделан из нескольких
<details> и <summary>. Также демонстрируется новый псевдо-элемент ::details-content и свойство interpolate-size: allow-keywords для анимации раскрытия.Вот аккордеон можно использовать вместо решений на JS, это не хак. Тут ещё можно углубиться в различия аккордеона и раскрываемых панелей, но в другой раз. А примеры диалога, меню, подсказки и вкладок из видео использовать не стоит.
#html #css #js #ui
👍7❤1🤝1
Пример приложения на чистом Node.js и Web API
Я не так давно делился мнением по поводу высказывания Тимура Шемсединова о том, что фронтенд фреймворки не нужны и это инерция. Я неоднократно видел, что подход разработки с использованием встроенных Web API вполне возможен.
Тимур поделился репозиторием с proof of concept своей мысли. Это приложение редактирования профиля: простой сервер с роутером на чистом Node.js и фронтенд в SPA-стиле на ES-модулях, веб-компонентах c Shadow DOM и шаблонами.
Приложение позволяет смотреть, искать, создавать, изменять и удалять профили экспертов с валидацией данных на клиенте и сервере, вычисляемыми полями и общей выделенной доменной логикой для клиента и сервера, не простой CRUD.
Особенность проекта в том, что он целиком построен на чистом Node.js и браузерных API и не использует рантайм-зависимости, фреймворки и сборщики. Это пример ровно того подхода, о котором говорил Тимур. Ограничения прописаны в репозитории:
- Запросы данных напрямую из компонентов запрещены;
- Только встроенные API;
- Никаких рантайм-зависимостей из npm, dev-зависимости допустимы, но опциональны (проект использует ESLint и Prettier);
- Чистый Node.js для серверной части;
- Стандартные ES-модули на клиенте;
- Веб-компоненты, Template API и Navigation API на клиенте;
-
В репозитории проекта есть подробный README с описанием архитектуры сервера и клиента, выделенной доменной логики, валидации, роутинга, декларативного рендеринга, шаблонов, сборки страниц, API, хранилища, пользовательских сценариев.
Я изучил код. Мне всё понятно, код аккуратный и лаконичный, есть чёткая структура, понятно, где что находится и как это расширять. И нет никаких монструозных абстракций, которых все боятся, когда речь о разработке на чистом Web API.
Да, это не похоже на общепринятый «индустриальный стандарт». Тут нет декларативных шаблонов с реактивностью, сложного клиентского состояния, а само приложение ориентировано на сервер.
Зато ноль зависимостей, не нужно думать о tree shaking, смотреть bundle analyzer, искать дубликаты, регулярно обновляться, следить за релизами и уязвимостями, слать issue и ждать релиз с исправлением бага, бороться с ограничениями, конфигурировать сборку.
Весь код полностью доступен, его можно доработать под потребности, он решает только проектные задачи, лишнее можно удалить, чтобы не висело мёртвым грузом, недостающие абстракции можно дописать, с LLM это довольно быстро.
Многие команды застревают в поддержке. Проект работает на старых версиях, уходят месяцы на обновления и оптимизацию бандлов, выделяются отдельные специалисты или инфраструктурные команды (кто-то называет их FrontOps).
Я вижу тут компромисс и trade off: DX, некоторые удобства, синтаксический сахар и «индустриальный стандарт» меняется на простоту поддержки, устойчивость, долговечность и полное владение кодовой базой.
Снижается паразитная сложность, система становится менее громоздкой, упрощается деплой и поддержка. Сложность становится контролируемой. Но это требует опыта, дисциплины, хорошего знания стандартов и Web API.
В процессе возникает «фреймворк», хотя это набор специфичных для проекта решений, что лично я бы фреймворком не назвал. Пусть будет «свой велосипед». React тоже был «своим велосипедом» для решения проблем команды Facebook.
Возможно, я предвзят, потому что сам предпочитаю работать со стандартными API и не люблю лишние зависимости. В любом случае, советую посмотреть проект и заложенные там идеи. Без фреймворков писать можно и это не так страшно, сколько непривычно.
#js #web_api #architecture
Я не так давно делился мнением по поводу высказывания Тимура Шемсединова о том, что фронтенд фреймворки не нужны и это инерция. Я неоднократно видел, что подход разработки с использованием встроенных Web API вполне возможен.
Тимур поделился репозиторием с proof of concept своей мысли. Это приложение редактирования профиля: простой сервер с роутером на чистом Node.js и фронтенд в SPA-стиле на ES-модулях, веб-компонентах c Shadow DOM и шаблонами.
Приложение позволяет смотреть, искать, создавать, изменять и удалять профили экспертов с валидацией данных на клиенте и сервере, вычисляемыми полями и общей выделенной доменной логикой для клиента и сервера, не простой CRUD.
Особенность проекта в том, что он целиком построен на чистом Node.js и браузерных API и не использует рантайм-зависимости, фреймворки и сборщики. Это пример ровно того подхода, о котором говорил Тимур. Ограничения прописаны в репозитории:
- Запросы данных напрямую из компонентов запрещены;
- Только встроенные API;
- Никаких рантайм-зависимостей из npm, dev-зависимости допустимы, но опциональны (проект использует ESLint и Prettier);
- Чистый Node.js для серверной части;
- Стандартные ES-модули на клиенте;
- Веб-компоненты, Template API и Navigation API на клиенте;
-
<template> для фрагментов UI и веб-компонентов с Shadow DOM, где уместно.В репозитории проекта есть подробный README с описанием архитектуры сервера и клиента, выделенной доменной логики, валидации, роутинга, декларативного рендеринга, шаблонов, сборки страниц, API, хранилища, пользовательских сценариев.
Я изучил код. Мне всё понятно, код аккуратный и лаконичный, есть чёткая структура, понятно, где что находится и как это расширять. И нет никаких монструозных абстракций, которых все боятся, когда речь о разработке на чистом Web API.
Да, это не похоже на общепринятый «индустриальный стандарт». Тут нет декларативных шаблонов с реактивностью, сложного клиентского состояния, а само приложение ориентировано на сервер.
Зато ноль зависимостей, не нужно думать о tree shaking, смотреть bundle analyzer, искать дубликаты, регулярно обновляться, следить за релизами и уязвимостями, слать issue и ждать релиз с исправлением бага, бороться с ограничениями, конфигурировать сборку.
Весь код полностью доступен, его можно доработать под потребности, он решает только проектные задачи, лишнее можно удалить, чтобы не висело мёртвым грузом, недостающие абстракции можно дописать, с LLM это довольно быстро.
Многие команды застревают в поддержке. Проект работает на старых версиях, уходят месяцы на обновления и оптимизацию бандлов, выделяются отдельные специалисты или инфраструктурные команды (кто-то называет их FrontOps).
Я вижу тут компромисс и trade off: DX, некоторые удобства, синтаксический сахар и «индустриальный стандарт» меняется на простоту поддержки, устойчивость, долговечность и полное владение кодовой базой.
Снижается паразитная сложность, система становится менее громоздкой, упрощается деплой и поддержка. Сложность становится контролируемой. Но это требует опыта, дисциплины, хорошего знания стандартов и Web API.
В процессе возникает «фреймворк», хотя это набор специфичных для проекта решений, что лично я бы фреймворком не назвал. Пусть будет «свой велосипед». React тоже был «своим велосипедом» для решения проблем команды Facebook.
Возможно, я предвзят, потому что сам предпочитаю работать со стандартными API и не люблю лишние зависимости. В любом случае, советую посмотреть проект и заложенные там идеи. Без фреймворков писать можно и это не так страшно, сколько непривычно.
#js #web_api #architecture
GitHub
GitHub - HowProgrammingWorks/WebComponents: WebComponents
WebComponents. Contribute to HowProgrammingWorks/WebComponents development by creating an account on GitHub.
👍11🥱10🤡4🤮3💅3❤1❤🔥1
Пустые кнопки и ссылки
По данным отчёта WebAIM Million 2026 на 46.3% сайтов встречаются пустые ссылки и на 30.6% сайтов — пустые кнопки. Обе эти проблемы входят в топ 6 самых частых нарушений доступности, обнаруживаемых с помощью WAVE.
Пустые кнопки и ссылки — это те, у которых имя не задано ни одним из способов и браузер вычисляет его как пустую строку. Вспомогательные технологии используют имя для идентификации элементов, а люди полагаются на это при взаимодействии.
- Программы чтения с экрана озвучивают тип элемента и его имя: «Каталог, ссылка» или «Добавить в корзину, кнопка». Пользователь слышит и понимает, что за элемент и что он делает;
- Программы голосового управления ищут элементы по имени: «Нажми Каталог» или «Нажми Добавить в корзину» программа найдёт элемент на экране и нажмёт на него;
- Программы чтения с экрана и специальные браузерные расширения выводят все ссылки или кнопки со страницы в виде списка, имя используется при формировании этого списка.
При отсутствии имени элементы будут анонимными. Просто какая-то «Ссылка» или «Кнопка». Не понятно назначение, сложно идентифицировать, не удобно взаимодействовать. Всё это создаёт препятствия для пользователей.
Чаще всего пустые ссылки и кнопки получаются, когда они отображаются в виде иконок: три горизонтальные линии, тележка, крестик, урна, стрелка, плюс и так далее. Визуально может быть понятно, но программно — нет.
Это примеры «пустых» кнопок и ссылок без имени. Базовое правило таково: у кнопок и ссылок должно быть короткое, лаконичное и понятное имя, заданное одним из способов:
- атрибут
- атрибут
- элемент
- текстовый контент;
- атрибут
Порядок указывает приоритет применения.
Наилучшим из способов будет видимый текстовый контент. Он соответствует первому правилу ARIA: не полагаться на атрибуты ARIA и использовать встроенные способы. Также видимый текст можно прочесть в отличие от скрытого.
То есть кнопка или ссылка с иконкой и текстом — лучшее из возможных решений. Глядя на текст становится понятно, что нужно сказать для активации элемента голосом. Также люди с когнитивными нарушениями могут не понимать метафору иконки.
При наличии видимого текста стоит скрыть иконки, если они выполняют только функцию визуальной подсказки и текст уже описывает это. Подойдёт атрибут
Видимый контент это хорошо, но не всегда возможно, потому что часто дизайнеры против лишнего визуального шума и загромождения интерфейса, особенно на мобильных. Поэтому распространены именно ссылки и кнопки только с иконками.
В таком случае придётся прибегнуть к скрытым подписям, которые задают имя, но не видны в интерфейсе. Если следовать всё тому же правилу ARIA, то есть несколько способов задать скрытое имя без использования атрибутов ARIA:
- Элемент
- Специальный класс
- Атрибут
- Атрибут
Элемент
Если прибегнуть к ARIA, то имя кнопок и ссылок можно задать с помощью атрибутов
-
-
- самый простой и короткий способ — просто указать ссылке или кнопке атрибут
Какой бы способ вы ни выбрали, всегда проверяйте значение Name у элемента на панели Accessibility в DevTools и проходитесь программой чтения с экрана. Не лишним будет прогнать страницу через Axe и подключить линтеры.
#html #a11y
По данным отчёта WebAIM Million 2026 на 46.3% сайтов встречаются пустые ссылки и на 30.6% сайтов — пустые кнопки. Обе эти проблемы входят в топ 6 самых частых нарушений доступности, обнаруживаемых с помощью WAVE.
Пустые кнопки и ссылки — это те, у которых имя не задано ни одним из способов и браузер вычисляет его как пустую строку. Вспомогательные технологии используют имя для идентификации элементов, а люди полагаются на это при взаимодействии.
- Программы чтения с экрана озвучивают тип элемента и его имя: «Каталог, ссылка» или «Добавить в корзину, кнопка». Пользователь слышит и понимает, что за элемент и что он делает;
- Программы голосового управления ищут элементы по имени: «Нажми Каталог» или «Нажми Добавить в корзину» программа найдёт элемент на экране и нажмёт на него;
- Программы чтения с экрана и специальные браузерные расширения выводят все ссылки или кнопки со страницы в виде списка, имя используется при формировании этого списка.
При отсутствии имени элементы будут анонимными. Просто какая-то «Ссылка» или «Кнопка». Не понятно назначение, сложно идентифицировать, не удобно взаимодействовать. Всё это создаёт препятствия для пользователей.
Чаще всего пустые ссылки и кнопки получаются, когда они отображаются в виде иконок: три горизонтальные линии, тележка, крестик, урна, стрелка, плюс и так далее. Визуально может быть понятно, но программно — нет.
<button type="button">
<svg>
<!-- иконка с тремя линиями -->
</svg>
</button>
<a
href="/cart"
class="icon icon--cart"
>
<!-- иконка тележки в CSS -->
</a>
<button type="button">
<i class="fa-solid fa-trash">
<!-- иконка мусорки из шрифта -->
</i>
</button>
<a href="/catalog?page=3">
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt=""
>
</a>
Это примеры «пустых» кнопок и ссылок без имени. Базовое правило таково: у кнопок и ссылок должно быть короткое, лаконичное и понятное имя, заданное одним из способов:
- атрибут
aria-labelledby;- атрибут
aria-label;- элемент
<label> (только для <button>);- текстовый контент;
- атрибут
title.Порядок указывает приоритет применения.
aria-label переопределяет имя, заданное через <label>, а aria-labelledby, в свою очередь, переопределяет имя, заданное в aria-label. Стоит выбрать какой-то один способ и не смешивать во избежание неожиданностей.Наилучшим из способов будет видимый текстовый контент. Он соответствует первому правилу ARIA: не полагаться на атрибуты ARIA и использовать встроенные способы. Также видимый текст можно прочесть в отличие от скрытого.
То есть кнопка или ссылка с иконкой и текстом — лучшее из возможных решений. Глядя на текст становится понятно, что нужно сказать для активации элемента голосом. Также люди с когнитивными нарушениями могут не понимать метафору иконки.
<button type="button">
<svg aria-hidden="true">
<!-- иконка с тремя линиями -->
</svg>
Меню
</button>
<a
href="/cart"
class="icon icon--cart"
>
<!-- иконка тележки в CSS -->
Корзина
</a>
<label for="delete">
Удалить
</label>
<button type="button" id="delete">
<i
class="fa-solid fa-trash"
aria-hidden="true"
>
<!-- иконка мусорки из шрифта -->
</i>
</button>
<a href="/catalog?page=3">
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt=""
>
Предыдущая страница
</a>
При наличии видимого текста стоит скрыть иконки, если они выполняют только функцию визуальной подсказки и текст уже описывает это. Подойдёт атрибут
aria-hidden="true" или пустой alt="" у <img>, что скрывает элементы из дерева доступности.Видимый контент это хорошо, но не всегда возможно, потому что часто дизайнеры против лишнего визуального шума и загромождения интерфейса, особенно на мобильных. Поэтому распространены именно ссылки и кнопки только с иконками.
В таком случае придётся прибегнуть к скрытым подписям, которые задают имя, но не видны в интерфейсе. Если следовать всё тому же правилу ARIA, то есть несколько способов задать скрытое имя без использования атрибутов ARIA:
- Элемент
<title> внутри <svg> задаёт альтернативный текст для изображения-иконки (работает как alt у <img>) и используется как текстовый контент для вычисления имени;- Специальный класс
visually-hidden делает элемент визуально невидимым, но всё ещё доступным как текстовый контент, который задаёт имя;- Атрибут
title задаёт имя элементу при отсутствии контента, но текст в атрибуте отображается в виде системной всплывающей подсказки только при наведении (и при фокусе в Edge);- Атрибут
alt задаёт альтернативный текст для изображения и его значение также используется как текстовый контент и задаёт имя элементу.Элемент
<title> и атрибут title создают системные всплывающие подсказки. C ними много проблем: появляются только при наведении мыши, не реагируют на настройки размера текста и так далее. Не рекомендуется их использовать.<button type="button">
<svg>
<title>
Меню
</title>
<!-- иконка с тремя линиями -->
</svg>
</button>
<a
href="/cart"
class="icon icon--cart"
>
<!-- иконка тележки в CSS -->
<span class="visually-hidden">
Корзина
</span>
</a>
<button
type="button"
title="Удалить"
>
<i class="fa-solid fa-trash">
<!-- иконка мусорки из шрифта -->
</i>
</button>
<a href="/catalog?page=3">
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt="Предыдущая страница"
>
</a>
Если прибегнуть к ARIA, то имя кнопок и ссылок можно задать с помощью атрибутов
aria-label или aria-labelledby. Можно указать как на самих элементах, так и на иконках в виде альтернативного текста, который будет использован как текстовый контент кнопки.<button type="button">
<svg
role="img"
aria-label="Меню"
>
<!-- иконка с тремя линиями -->
</svg>
</button>
<a
href="/cart"
class="icon icon--cart"
aria-labelledby="cart-label"
>
<!-- иконка тележки в CSS -->
<span id="cart-label" hidden>
Корзина
</span>
</a>
<span id="del-icon" hidden>
Удалить
</span>
<button type="button">
<i
class="fa-solid fa-trash"
role="img"
aria-labelledby="del-icon"
>
<!-- иконка мусорки из шрифта -->
</i>
</button>
<a
href="/catalog?page=3"
aria-label="Предыдущая страница"
>
<!-- внешняя иконка стрелки -->
<img
src="/assets/arrow-left.svg"
alt=""
>
</a>
- role="img" превращает <svg> в <img>, а aria-label в таком случае работает как alt. Альтернативный текст используется как имя элемента;-
aria-labelledby ссылается на элемент по указанному id и текст этого элемента используется как имя, при этом сам элемент может быть скрыт;-
aria-labelledby также работает как alt для элементов с role="img" и берёт альтернативный текст из указанного элемента;- самый простой и короткий способ — просто указать ссылке или кнопке атрибут
aria-label, который задаёт имя элементу.Какой бы способ вы ни выбрали, всегда проверяйте значение Name у элемента на панели Accessibility в DevTools и проходитесь программой чтения с экрана. Не лишним будет прогнать страницу через Axe и подключить линтеры.
#html #a11y
👍8❤2⚡1🔥1
Вау-эффекты и проблемы гидратации
Прочитал пост в канале Максима Морева о вау-эффектах на сайтах. Контекст: сайт документации drag-n-drop плагина для Vue создан на VitePress и на страницах есть мешающие чтению визуальные эффекты. Красиво, но не практично.
Я решил зайти на сайт со своего телефона. Модель не флагманская, но относится к high-end категории. Я увидел… шапку с логотипом, иконкой поиска и бургером, переливающуюся полоску, пустоту и подвал с копирайтом.
При нажатии на бургер, иконка меняется на крестик, но меню не открывается. При нажатии на поиск перенаправляет на страницу поиска, но поля ввода не видно. Нажатие на логотип возвращает на главную. Везде пустота.
Шанс моего ухода с такого сайта 100%, я не вижу буквально ничего, сайт бесполезен. Причина, как выяснилось, в гидратации. Где-то SSR HTML не сошёлся с клиентским деревом компонентов и у контента не удалилось свойство
Досадная ошибка, которая сделала сайт бесполезным. Все мы допускаем ошибки и это нормально. Но не будь этот сайт создан на VitePress с гидратацией на клиенте и вау-эффектами, эта ошибка бы технически не могла возникнуть.
Это сайт документации — текст, блоки кода (тоже текст), демо и изображения. Контент статический и требует минимального JS для меню, поиска, переключения вкладок и подобных виджетов. Цель сайта — дать информацию, а не показать эффекты.
Нет ни единого повода добавлять на такой сайт гидратацию, клиентский роутинг, реактивность и компонентную модель Vue. Это всё обходится сайту в 262кб (1.5мб без cжатия) JS и сопутствующими затратами на его обработку без какой-то пользы.
Набор предварительно сгенерированных лёгких HTML-страниц (SSG), точечный JS для виджетов, навигация ссылками
VitePress умеет работать в режиме MPA без JS, но экспериментально. Альтернатива — Astro или любой генератор статических сайтов без JS в рантайме по умолчанию. Это проще, надёжнее, производительнее и не будет никаких ошибок гидратации.
#js #architecture
Прочитал пост в канале Максима Морева о вау-эффектах на сайтах. Контекст: сайт документации drag-n-drop плагина для Vue создан на VitePress и на страницах есть мешающие чтению визуальные эффекты. Красиво, но не практично.
Я решил зайти на сайт со своего телефона. Модель не флагманская, но относится к high-end категории. Я увидел… шапку с логотипом, иконкой поиска и бургером, переливающуюся полоску, пустоту и подвал с копирайтом.
При нажатии на бургер, иконка меняется на крестик, но меню не открывается. При нажатии на поиск перенаправляет на страницу поиска, но поля ввода не видно. Нажатие на логотип возвращает на главную. Везде пустота.
Шанс моего ухода с такого сайта 100%, я не вижу буквально ничего, сайт бесполезен. Причина, как выяснилось, в гидратации. Где-то SSR HTML не сошёлся с клиентским деревом компонентов и у контента не удалилось свойство
opacity: 0.Досадная ошибка, которая сделала сайт бесполезным. Все мы допускаем ошибки и это нормально. Но не будь этот сайт создан на VitePress с гидратацией на клиенте и вау-эффектами, эта ошибка бы технически не могла возникнуть.
Это сайт документации — текст, блоки кода (тоже текст), демо и изображения. Контент статический и требует минимального JS для меню, поиска, переключения вкладок и подобных виджетов. Цель сайта — дать информацию, а не показать эффекты.
Нет ни единого повода добавлять на такой сайт гидратацию, клиентский роутинг, реактивность и компонентную модель Vue. Это всё обходится сайту в 262кб (1.5мб без cжатия) JS и сопутствующими затратами на его обработку без какой-то пользы.
Набор предварительно сгенерированных лёгких HTML-страниц (SSG), точечный JS для виджетов, навигация ссылками
<a>, View Transition, предварительная загрузка и Speculation Rules дадут тот же эффект «мгновенной навигации SPA» без JS.VitePress умеет работать в режиме MPA без JS, но экспериментально. Альтернатива — Astro или любой генератор статических сайтов без JS в рантайме по умолчанию. Это проще, надёжнее, производительнее и не будет никаких ошибок гидратации.
#js #architecture
Telegram
Максим Морев
Про вау-эффекты и прочие свистоперделки
Наткнулся тут на вот такой сайтик — документацию по библиотеке для Drag&Drop во Vue.
Зашёл (на десктопе) и скривился — сомнительное удовольствие читать текст на переливающемся фоне, отвлекает от содержания.
Ну, думаю…
Наткнулся тут на вот такой сайтик — документацию по библиотеке для Drag&Drop во Vue.
Зашёл (на десктопе) и скривился — сомнительное удовольствие читать текст на переливающемся фоне, отвлекает от содержания.
Ну, думаю…
👍9💯3🤝2❤1🔥1👾1
Prop for that
Адам Аргайл выпустил небольшую JS-библиотеку prop-for-that, которая следит за различными параметрами страницы и записывает значения в пользовательские свойства CSS. Это позволяет писать стили на основе значений этих свойств.
Что библиотека может отслеживать:
- Положение курсора (x, y) в px и % от области просмотра;
- Размер области просмотра;
- Текущее время (часы, минуты, секунды, текущий timestamp);
- Количество кадров в секунду;
- Онлайн-статус;
- Состояние видимости и фокусировки страницы;
- Параметры сети (тип, downlink, rtt, режим экономии данных);
- Состояние батареи (процент заряда, заряжается ли);
- Нагрузку на CPU;
- Прокрутку (направление и скорость);
- Визуальную область просмотра (pinch-zoom, отображение виртуальной клавиатуры);
- Виртуальную клавиатуру (открыта ли, размеры, координаты);
- Ориентацию устройства;
- Параметры акселерометра;
- Геолокацию;
- Плотность пикселей экрана;
- Количество ядер процессора;
- Доступный объём оперативной памяти;
- Ширину полосы прокрутки;
- Тип навигации;
- Мета-данные (
- Размеры элемента;
- Видимость элемента;
- Значение
- Свойства текстовых полей (длина, пустое ли, валидное ли, лимит символов);
- Состояние валидности полей ввода;
- Состояния полей («чистое», «грязное», тронутое, нетронутое, изменённое, отправленное);
- Количество полей (валидных, не валидных, заполненных);
- Состояния
- Цвет из
- Состояния
- Состояния
- Цвета
- Цвета
- Состояние урезанного текста (
Достаточно большой список. Плюс к этому есть JS API и система плагинов, поэтому библиотеку можно расширять. Некоторые свойства глобальные, как состояние сети, процессора или батареи. Такие свойства записываются в
Другие свойства работают на уровне элементов. Чтобы библиотека отслеживала свойства, нужно указать атрибут
В примере указано, что нужно отслеживать размеры (
В документации много примеров, где и как это можно применить. Особенно хорошо это работает в сочетании с Container Style Queries и функцией
Счётчики и псевдо-элементы со свойством
#css #js
Адам Аргайл выпустил небольшую JS-библиотеку prop-for-that, которая следит за различными параметрами страницы и записывает значения в пользовательские свойства CSS. Это позволяет писать стили на основе значений этих свойств.
Что библиотека может отслеживать:
- Положение курсора (x, y) в px и % от области просмотра;
- Размер области просмотра;
- Текущее время (часы, минуты, секунды, текущий timestamp);
- Количество кадров в секунду;
- Онлайн-статус;
- Состояние видимости и фокусировки страницы;
- Параметры сети (тип, downlink, rtt, режим экономии данных);
- Состояние батареи (процент заряда, заряжается ли);
- Нагрузку на CPU;
- Прокрутку (направление и скорость);
- Визуальную область просмотра (pinch-zoom, отображение виртуальной клавиатуры);
- Виртуальную клавиатуру (открыта ли, размеры, координаты);
- Ориентацию устройства;
- Параметры акселерометра;
- Геолокацию;
- Плотность пикселей экрана;
- Количество ядер процессора;
- Доступный объём оперативной памяти;
- Ширину полосы прокрутки;
- Тип навигации;
- Мета-данные (
theme-color, og-image, color-scheme);- Размеры элемента;
- Видимость элемента;
- Значение
<input type="range">;- Свойства текстовых полей (длина, пустое ли, валидное ли, лимит символов);
- Состояние валидности полей ввода;
- Состояния полей («чистое», «грязное», тронутое, нетронутое, изменённое, отправленное);
- Количество полей (валидных, не валидных, заполненных);
- Состояния
<select> (индекс, количество опций, количество выбранных опций, текущее значение);- Цвет из
<input type="color">;- Состояния
<audio> и <video> (прогресс, текущее время, длительность, пауза, громкость);- Состояния
<img> (физические размеры, загружено ли, ошибка загрузки);- Цвета
<img> (доминантный, акцентный, тёмный, светлый, средний, температура);- Цвета
<video> (доминантный, акцентный);- Состояние урезанного текста (
line-clamp).Достаточно большой список. Плюс к этому есть JS API и система плагинов, поэтому библиотеку можно расширять. Некоторые свойства глобальные, как состояние сети, процессора или батареи. Такие свойства записываются в
:root.Другие свойства работают на уровне элементов. Чтобы библиотека отслеживала свойства, нужно указать атрибут
data-props-for у элемента и перечислить через запятую названия отслеживаемых свойств. По умолчанию ничего не отслеживается.<div
class="box"
data-props-for="size"
style="resize: both"
>
</div>
<style>
.box::after {
counter-reset: w calc(var(--live-w)) h calc(var(--live-h));
content: counter(w) ' × ' counter(h);
}
</style>
В примере указано, что нужно отслеживать размеры (
data-props-for="size"). В CSS будут доступны свойства --live-w и --live-h с актуальными значениями. Для примера они выводятся в элементе с помощью счётчиков.В документации много примеров, где и как это можно применить. Особенно хорошо это работает в сочетании с Container Style Queries и функцией
if(), позволяя делать динамическую стилизацию на основе значений свойств.Счётчики и псевдо-элементы со свойством
content можно использовать для вывода значений в интерфейсе. Также можно скрывать или показывать отдельные узлы по условию. В общем, фантазии хватает как это можно применить.#css #js
👍12😍1
Отсутствующие подписи для полей
Более половины сайтов (51%) по данным отчёта WebAIM Million 2026 содержат поля ввода без подписей. У полей нет имени и нельзя идентифицировать какие данные необходимо ввести. Это одна из 6 самых частых ошибок в WAVE.
Исправить эту ошибку не сложно. Нужно указать подпись (имя) одним из способов. Порядок отражает приоритет применения:
-
-
-
-
-
-
Лучше всего указывать видимые подписи в
Атрибут
Иногда дизайнеры рисуют подпись внутри поля и это выглядит как заполнитель. В таком случае разработчик может указать атрибут
Когда подпись находится внутри поля, можно прибегнуть к технике плавающих подписей. Это когда при фокусе на поле, подпись подъезжает вверх и остаётся видимой. Техника не лишена проблем, но это лучше, чем подпись в
Что касается критериев, применимых к подписям, то их пять:
- 1.3.1 Info and Relationship — подпись должна быть программно связана с полем, а её визуальная информация программно обозначена;
- 2.4.6 Headings and Labels — подпись, если она есть, должна быть понятной и описательной;
- 2.5.3 Label in Name — видимая подпись должна полностью или частично соответствовать программно заданному имени поля;
- 3.3.2 Labels or Instructions — у полей должна быть видимая подпись или инструкция для обозначения требуемой информации;
- 4.1.2 Name, Role, Value — у поля должно быть программно заданное имя.
Вариант с
#html #a11y
Более половины сайтов (51%) по данным отчёта WebAIM Million 2026 содержат поля ввода без подписей. У полей нет имени и нельзя идентифицировать какие данные необходимо ввести. Это одна из 6 самых частых ошибок в WAVE.
Исправить эту ошибку не сложно. Нужно указать подпись (имя) одним из способов. Порядок отражает приоритет применения:
-
aria-labelledby-
aria-label-
<label>-
title-
placeholder-
aria-placeholderЛучше всего указывать видимые подписи в
<label> и связывать их с полями через for и id. Или оборачивать в <label> с подписью внутри. Эти варианты не требуют ARIA, что соответствует первому правилу. Поэтому они предпочтительны.<label for="first_name">
Имя (обязательно)
</label>
<input
type="text"
name="first_name"
id="first_name"
autocomplete="given-name"
autocapitalize="words"
placeholder="Алексей"
required
>
<label>
Имя (обязательно)
<input
type="text"
name="first_name"
autocomplete="given-name"
autocapitalize="words"
placeholder="Алексей"
required
>
</label>
Атрибут
title использовать не стоит. Он задаёт имя полю, но также создаёт системную всплывающую подсказку. Эта подсказка не соответствует требованиям доступности по критериям 1.4.4, 1.4.10, 1. 4.12, 1.4.13.Иногда дизайнеры рисуют подпись внутри поля и это выглядит как заполнитель. В таком случае разработчик может указать атрибут
placeholder. Хотя он задаёт имя полю, он предназначен не для этого. Используйте атрибут по назначению.Когда подпись находится внутри поля, можно прибегнуть к технике плавающих подписей. Это когда при фокусе на поле, подпись подъезжает вверх и остаётся видимой. Техника не лишена проблем, но это лучше, чем подпись в
placeholder.aria-label можно применить для быстрого исправления отсутствующей подписи, но она не будет видна визуально. Это нарушает один из критериев WCAG и ухудшает доступность. Поэтому лучше избегать aria-label для подписей.aria-labelledby работает как <label>, но наоборот: поле ссылается по id на элемент, который действует как подпись. Такой способ подойдёт для нестандартных полей ввода или если нет возможности добавить <label> в разметку.Что касается критериев, применимых к подписям, то их пять:
- 1.3.1 Info and Relationship — подпись должна быть программно связана с полем, а её визуальная информация программно обозначена;
- 2.4.6 Headings and Labels — подпись, если она есть, должна быть понятной и описательной;
- 2.5.3 Label in Name — видимая подпись должна полностью или частично соответствовать программно заданному имени поля;
- 3.3.2 Labels or Instructions — у полей должна быть видимая подпись или инструкция для обозначения требуемой информации;
- 4.1.2 Name, Role, Value — у поля должно быть программно заданное имя.
Вариант с
<label> соответствует всем критериям, поэтому он предпочтительный. Всем критериям будет соответствовать вариант с aria-labelledby, ссылаясь на элемент с видимым описательным текстом. Это резервный вариант.<label for="first_name">
Имя (обязательно)
</label>
<input
type="text"
name="first_name"
id="first_name"
autocomplete="given-name"
autocapitalize="words"
placeholder="Алексей"
required
>
<span id="first_name">
Имя (обязательно)
</span>
<input
type="text"
name="first_name"
autocomplete="given-name"
autocapitalize="words"
placeholder="Алексей"
required
aria-labelledby="first_name"
>
#html #a11y
👍12❤1❤🔥1
CSS Linked Parameters
При использовании встроенных SVG-иконок в HTML удобно то, что к ним есть доступ в CSS. Можно, например, изменять цвета, скрывать отдельные части иконки, менять толщину линий, радиус окружности, применять анимации и так далее.
Однако при использовании внешних SVG-иконок доступ в CSS теряется. Отчасти это можно обойти через SVG-спрайты, но у них есть свои нюансы. CSSWG выпустила черновик CSS Linked Parameters, который предлагает решение проблемы.
Суть предложения в том, чтобы передавать через URL специальные параметры и затем получать к ним доступ через переменные окружения в атрибутах и CSS. Так можно будет передать цвет во внешний SVG-файл, подключаемый через
Можно передавать несколько параметров, перечислив их в URL через
Таким образом появляется возможность передавать данные во внешние файлы. Основное назначение —
#html #svg #css
При использовании встроенных SVG-иконок в HTML удобно то, что к ним есть доступ в CSS. Можно, например, изменять цвета, скрывать отдельные части иконки, менять толщину линий, радиус окружности, применять анимации и так далее.
<a href="...">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="..."/>
</svg>
Назад
</a>
<style>
a {
color: var(--color-link);
transition: color .3s linear;
svg path {
fill: currentColor;
transition: fill .3s linear;
}
}
a:hover {
color: var(--color-link-hover);
}
</style>
Однако при использовании внешних SVG-иконок доступ в CSS теряется. Отчасти это можно обойти через SVG-спрайты, но у них есть свои нюансы. CSSWG выпустила черновик CSS Linked Parameters, который предлагает решение проблемы.
Суть предложения в том, чтобы передавать через URL специальные параметры и затем получать к ним доступ через переменные окружения в атрибутах и CSS. Так можно будет передать цвет во внешний SVG-файл, подключаемый через
<img> или url().Дисклеймер: это обзор раннего предложения новых функций. Синтаксис может измениться в будущем или от функций могут отказаться
<!--
#param() задаёт параметр
--color со значением grern
-->
<img src="icon.svg#param(--color,green)">
<img src="icon.svg">
<style>
img {
/*
Параметры можно задать в CSS
с помощью link-parameters.
Это добавит к src и
ссылкам на все ресурсы
#param(--color,green)
*/
link-parameters:
param(--color, green)
;
}
.icon {
/*
Параметры можно задать
в функции url() в CSS
*/
background-image:
url(
"icon.svg",
param(--color, green)
)
;
}
</style>
<!-- icon.svg -->
<svg>
<!--
env() считывает переданный
в URL параметр --color, и
устанавливает в атрибут fill,
значение по умолчанию black
-->
<path
fill="env(--color, black)"
d="..."
/>
</svg>
<!-- icon.svg -->
<svg>
<!-- можно задать в CSS -->
<style>
path {
fill: env(--color, black);
}
</style>
<path d="..."/>
</svg>
Можно передавать несколько параметров, перечислив их в URL через
&, указав несколько param() через пробел в url() или через запятую в link-parameters. В качестве значения могут быть пользовательские свойства CSS.<!-- параметры в URL через & -->
<img src="icon.svg#param(--color,green)¶m(--stroke,1)">
<img src="icon.svg">
<style>
img {
/*
несколько param() в link-parameters,
доступны пользовательские свойства
*/
link-parameters:
param(--color, var(--color-primary)),
param(--stroke, 1)
;
}
.icon {
/*
несколько param() в url(),
доступны пользовательские свойства
*/
background-image:
url(
"icon.svg",
param(--color, var(--color-primary))
param(--stroke, 1)
)
;
}
</style>
Таким образом появляется возможность передавать данные во внешние файлы. Основное назначение —
<svg>, но также упоминается возможность передачи для <iframe>. Синтаксис фрагментов используется для обратной совместимости.#html #svg #css
👍12🔥2😍1
Эффект съезда с тротуара
Читая материал о доступности, встретился с феноменом «эффект съезда с тротуара» (Curb cut effect). Его суть показалась мне интересной, чтобы написать и поделиться своими мыслями в виде поста.
Представьте проезжую часть и тротуар с бордюром вдоль неё. В некоторых местах есть съезды: бордюр спущен на уровень проезжей части, а сам тротуар немного наклонён. Это сделано для устранения барьеров людям на инвалидных колясках.
Но также это помогает людям с детской коляской, сумкой на колёсиках, тележкой, велосипедом, самокатом, скейтбордом и другими средствами личной мобильности или вещами с колёсами. Ещё это помогает пожилым людям.
Эффект съезда с тротуара — это социально-экономический феномен, суть которого в том, что решения, изначально созданные для узкой группы людей, в конечном итоге оказываются полезными и эффективными для более широкой группы.
Доступность сайтов и приложений часто воспринимается как специфическая работа ради малой группы пользователей, которой можно пренебречь. Тут как раз действует эффект съезда с тротуара. Улучшение доступности сайта даст больший эффект.
Внедрение практик доступности окажет положительный эффект на всех. Причём эффект распространяется не только на людей, но и на машины. Отмечено влияние на поисковые роботы, агенты ИИ, разные парсеры и программы.
Вот несколько примеров:
- Хороший шрифт с достаточным размером и контрастными цветами улучшает читабельность сайта, пользователям удобнее читать;
- Субтитры позволят пользователям смотреть видео без звука и читать субтитры в шумном помещении, если нет наушников;
- Достаточно большие интерактивные элементы легче нажимать пальцами или стилусом на смартфоне или планшете с сенсорным экраном;
- Подписи, подсказки и автодополнение у полей ввода помогут пользователям быстрее заполнять формы с меньшим количеством ошибок;
- Хорошо размеченная с помощью семантического HTML страница более понятна поисковым работам, агентам, лучше разбирается в режиме чтения;
- Текстовая расшифровка видео позволяет использовать поиск по тексту, переводить его на другой язык и копировать для различных целей;
- Правильно заданный язык страницы и элементов помогает программе-переводчику определить язык и предложить перевод.
Примеров можно ещё много придумать. Суть в том, что доступность можно и нужно рассматривать не как специальную задачу по адаптации сайта, а как общее улучшение качества, которое скажется на разных его аспектах и пользователях.
#a11y
Читая материал о доступности, встретился с феноменом «эффект съезда с тротуара» (Curb cut effect). Его суть показалась мне интересной, чтобы написать и поделиться своими мыслями в виде поста.
Представьте проезжую часть и тротуар с бордюром вдоль неё. В некоторых местах есть съезды: бордюр спущен на уровень проезжей части, а сам тротуар немного наклонён. Это сделано для устранения барьеров людям на инвалидных колясках.
Но также это помогает людям с детской коляской, сумкой на колёсиках, тележкой, велосипедом, самокатом, скейтбордом и другими средствами личной мобильности или вещами с колёсами. Ещё это помогает пожилым людям.
Эффект съезда с тротуара — это социально-экономический феномен, суть которого в том, что решения, изначально созданные для узкой группы людей, в конечном итоге оказываются полезными и эффективными для более широкой группы.
Доступность сайтов и приложений часто воспринимается как специфическая работа ради малой группы пользователей, которой можно пренебречь. Тут как раз действует эффект съезда с тротуара. Улучшение доступности сайта даст больший эффект.
Внедрение практик доступности окажет положительный эффект на всех. Причём эффект распространяется не только на людей, но и на машины. Отмечено влияние на поисковые роботы, агенты ИИ, разные парсеры и программы.
Вот несколько примеров:
- Хороший шрифт с достаточным размером и контрастными цветами улучшает читабельность сайта, пользователям удобнее читать;
- Субтитры позволят пользователям смотреть видео без звука и читать субтитры в шумном помещении, если нет наушников;
- Достаточно большие интерактивные элементы легче нажимать пальцами или стилусом на смартфоне или планшете с сенсорным экраном;
- Подписи, подсказки и автодополнение у полей ввода помогут пользователям быстрее заполнять формы с меньшим количеством ошибок;
- Хорошо размеченная с помощью семантического HTML страница более понятна поисковым работам, агентам, лучше разбирается в режиме чтения;
- Текстовая расшифровка видео позволяет использовать поиск по тексту, переводить его на другой язык и копировать для различных целей;
- Правильно заданный язык страницы и элементов помогает программе-переводчику определить язык и предложить перевод.
Примеров можно ещё много придумать. Суть в том, что доступность можно и нужно рассматривать не как специальную задачу по адаптации сайта, а как общее улучшение качества, которое скажется на разных его аспектах и пользователях.
#a11y
Wikipedia
Curb cut effect
phenomenon of disability-friendly features also being appreciated by people in general
👍16🤗2
Язык документа и его частей
В посте, посвящённому всемирному дню осведомлённости о доступности, упоминалось, что на 13.5% сайтов не задан язык документа. Радует, что это не много по сравнению с другими проблемами. Не радует, что это всё ещё 13.5%.
Исправление крайне простое: нужно задать у корневого элемента страницы
На этом можно было бы и закончить пост. Просто добавьте атрибут и это исправит одну из топ 6 ошибок доступности, которую обнаруживает WAVE. Но я расскажу ещё некоторые особенности и фишки вокруг языка страницы.
От языка страницы зависит отображение некоторых элементов, в частности
Если сайт мультиязычный и хочется что-то менять в CSS в зависимости от языка, есть селектор
На странице могут быть элементы, контент которых не соответствует основному языку страницы: цитаты, термины, названия или переключатель языка. Такие элементы также нужно пометить соответствующим атрибутом
Вообще
Атрибут
Среди контента могут быть общепринятые термины, названия брендов или фразы, которые написаны на другом языке, но не должны переводиться автоматическими переводчиками. На этот случай существует атрибут
#html #css #a11y
В посте, посвящённому всемирному дню осведомлённости о доступности, упоминалось, что на 13.5% сайтов не задан язык документа. Радует, что это не много по сравнению с другими проблемами. Не радует, что это всё ещё 13.5%.
Исправление крайне простое: нужно задать у корневого элемента страницы
<html> атрибут lang со значением, которое соответствует основному языку контента на странице в формате BCP 47.<!-- Русский -->
<html lang="ru"></html>
<!-- Русский, Россия -->
<html lang="ru-RU"></html>
<!-- Английский -->
<html lang="en"></html>
<!-- Английский, Британия -->
<html lang="en-GB"></html>
<!-- Английский, США -->
<html lang="en-US"></html>
На этом можно было бы и закончить пост. Просто добавьте атрибут и это исправит одну из топ 6 ошибок доступности, которую обнаруживает WAVE. Но я расскажу ещё некоторые особенности и фишки вокруг языка страницы.
От языка страницы зависит отображение некоторых элементов, в частности
<q>. Он предназначен для встроенных цитат и обрамляет текст в кавычки. Вид кавычек меняется в зависимости от языка (ёлочки или лапки).Если сайт мультиязычный и хочется что-то менять в CSS в зависимости от языка, есть селектор
:lang(). Он более мощный, чем селектор по атрибуту html[lang="..."] из-за масок и работы с вычисленным языком, а не значением в атрибуте.ol:lang(en-US) > li::marker {
/*
Маркеры списка 1) 2) 3) для американскго английского
*/
content: counter(list-item) ') ';
}
ol:lang(ru, by, uk) > li::marker {
/*
Маркеры списка 1. 2. 3. для восточнославянских языков
*/
content: counter(list-item) '. ';
}
На странице могут быть элементы, контент которых не соответствует основному языку страницы: цитаты, термины, названия или переключатель языка. Такие элементы также нужно пометить соответствующим атрибутом
lang.Вообще
lang — глобальный атрибут и его можно указывать у любых элементов. Язык наследуется вглубь по дереву от ближайшего родителя с lang. Сам атрибут переопределяет унаследованный язык.<html lang="ru">
...
<body>
...
<button
type="button"
popovertarget="langs"
>
Язык
</button>
<dialog id="langs" popover>
<ul>
<li>
<a
href="/ru"
aria-current="true"
>
Русский
</a>
</li>
<li>
<a
href="/en"
lang="en"
hreflang="en"
>
English
</a>
</li>
<li>
<a
href="/es"
lang="es"
hreflang="es"
>
Español
</a>
</li>
...
</ul>
</dialog>
</body>
</html>
Атрибут
hreflang помогает роботам понять, что страница по ссылке на другом языке. Это важно при SEO-продвижении мультиязычного сайта. К этому ещё стоит добавить ссылки на альтернативные версии текущей страницы на других языках.
<head>
...
<link
rel="alternate"
href="/en/catalog"
hreflang="en"
lang="en"
title="Catalog"
>
<link
rel="alternate"
href="/es/catalog"
hreflang="es"
lang="es"
title="Catalogar"
>
...
</head>
Среди контента могут быть общепринятые термины, названия брендов или фразы, которые написаны на другом языке, но не должны переводиться автоматическими переводчиками. На этот случай существует атрибут
translate со значением no.<p><span lang="fr" translate="no">Vite</span> позволяет быстро собирать <span lang="en" translate="no">frontend</span>-проекты различной сложности.</p>
#html #css #a11y
🔥11❤4🤝2🌚1