Почему доступность в Rust — это не опция, а необходимость
Когда мы пишем на Rust, мы привыкли думать о безопасности памяти, скорости и нулевых абстракциях. Но есть ещё один аспект, который часто остаётся за кадром — accessibility (доступность). Многие разработчики считают, что это забота только фронтендеров или дизайнеров. На деле — каждый, кто пишет код на Rust, может сделать свои инструменты, библиотеки или веб-приложения удобными для людей с ограниченными возможностями.
По данным ВОЗ, более 1 миллиарда человек в мире имеют ту или иную форму инвалидности. Это огромная аудитория, которую мы теряем, если игнорируем инклюзивность в Rust. И речь не только о слепых пользователях — доступность помогает всем: от людей с временными травмами до тех, кто работает в шумной среде или за рулём.
В этой статье мы разберём, как внедрить a11y (сокращение от accessibility) в Rust-проекты разного типа: CLI-утилиты, веб-приложения и GUI. Вы увидите реальные примеры кода, которые можно сразу использовать в своих проектах.
Accessibility в CLI: делаем консоль удобной для всех
Казалось бы, терминал — это последнее место, где нужна доступность. Но именно здесь часто работают люди с нарушениями зрения или моторики. Доступность Rust CLI начинается с простых вещей:
- Чёткие сообщения об ошибках — используйте
eprintln!для вывода ошибок, чтобы их можно было отдельно перенаправить в лог или озвучить скринридером. - Цветовые схемы — не полагайтесь только на цвет. Добавляйте символы или текст:
[ОК],[ОШИБКА]. - Понятный вывод — избегайте сложных таблиц без подписей.
Вот пример минималистичного CLI-инструмента на Rust с учётом доступности:
use std::io::{self, Write};
fn main() {
print!("Введите ваше имя: ");
io::stdout().flush().unwrap();
let mut name = String::new();
io::stdin().read_line(&mut name).unwrap();
let name = name.trim();
if name.is_empty() {
eprintln!("[ОШИБКА] Имя не может быть пустым.");
std::process::exit(1);
}
println!("[ОК] Привет, {}! Рады видеть вас.", name);
}
Обратите внимание: мы используем eprintln! для ошибок — это стандартный способ доступности в Rust CLI. Пользователь может перенаправить stderr в отдельный поток или файл, а скринридеры легче обрабатывают такой вывод.
Веб-доступность на Rust: Yew и WASM
Современные веб-фреймворки на Rust, такие как Yew, Leptos или Dioxus, позволяют создавать полноценные SPA. И здесь accessibility Rust веб — это не просто теги, а архитектурное решение.
Основные принципы WCAG (Web Content Accessibility Guidelines), которые нужно соблюдать:
- Контрастность — текст должен хорошо читаться на фоне.
- Навигация с клавиатуры — все элементы должны быть доступны через Tab.
- ARIA-атрибуты — дополнительные метки для скринридеров.
- Семантическая разметка — используйте правильные HTML-теги.
Пример компонента на Yew с учётом ARIA-атрибутов в Rust:
use yew::prelude::*;
#[function_component(AccessibleButton)]
pub fn accessible_button() -> Html {
html! {
<button
class="btn btn-primary"
aria-label="Отправить форму"
role="button"
tabindex="0"
onkeypress={|e| {
if e.key() == "Enter" || e.key() == " " {
// Обработка клика
}
}}
>
{ "Отправить" }
</button>
}
}
Здесь мы добавили aria-label для скринридера, role для явного указания роли и обработчик клавиатуры. Это база инклюзивного кода на Rust для веба.
GUI на Rust: доступность в нативных приложениях
Rust отлично подходит для создания нативных GUI с помощью egui, iced или slint. Но доступность в Rust GUI — это отдельная задача, потому что нативные приложения не имеют встроенной поддержки скринридеров, как веб.
Что можно сделать:
- Добавить текстовые метки для всех интерактивных элементов.
- Использовать системные настройки — например, тему высокой контрастности.
- Поддерживать навигацию с клавиатуры — Tab, Enter, Escape.
Пример на egui с фокусом на доступность Rust GUI:
use eframe::egui;
fn main() -> Result<(), eframe::Error> {
let options = eframe::NativeOptions::default();
eframe::run_native(
"Доступное приложение",
options,
Box::new(|_cc| Box::new(MyApp::default())),
)
}
struct MyApp {
name: String,
}
impl Default for MyApp {
fn default() -> Self {
Self {
name: String::new(),
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Введите ваше имя");
ui.text_edit_singleline(&mut self.name);
if ui.button("Приветствовать").clicked() {
// Действие
}
});
}
}
Для улучшения a11y в Rust GUI можно добавить ui.label с описанием поля ввода и проверять, что все элементы имеют уникальные ID для навигации.
Тестирование доступности в Rust
Мало написать код — нужно его проверить. Тестирование доступности Rust можно автоматизировать. Для веб-проектов на WASM используйте axe-core через WebDriver. Для CLI — пишите юнит-тесты.
Пример теста для CLI-инструмента на Rust, проверяющего инклюзивность в Rust:
#[cfg(test)]
mod tests {
use std::process::Command;
#[test]
fn test_error_output_to_stderr() {
let output = Command::new("cargo")
.args(&["run", "--", "--invalid"])
.output()
.expect("Не удалось запустить программу");
// Проверяем, что ошибка идёт в stderr
assert!(!output.stderr.is_empty(), "Ошибки должны быть в stderr");
assert!(output.status.success() == false, "Программа должна завершиться с ошибкой");
}
}