Інструменти
Які інструменти існують
Стан доступності можна частково перевіряти деякими інструментами, що:
-
зменшує кількість рутинних дій і економить час;
-
дає можливість поверхово оцінити стан доступності вебсайту;
-
допомагає отримати зразкові описи проблем і швидше підготувати звіт про доступність.
Наголошуємо
Автоматичні інструменти допомагають перевіряти доступність, але не можуть виявити всі проблеми. Навіть у межах однієї вимоги частина недоліків може залишитися непоміченою, тому для повної та якісної перевірки також потрібен ручний аналіз.
Аналізатори
Це розширення, які потрібно встановити у вашому браузері.
Accessibility Insights for Web
Аналізує сторінку, виводить список помилок і можливі способи їх усунення, допомагає протестувати порядок фокусування. Використовується при щорічному моніторингу вебдоступності відповідно до методики.
Lighthouse
Аналізує сторінку, виводить список помилок, до якого включаються невеликі скриншоти проблемних елементів.
WAVE
Розмічає сторінку і проблемні місця на ній за допомогою деталізованої системи іконок, надає інтерактивну панель для дослідження проблем.
Перевірка контрастності
Часто виникає потреба перевіряти контрастність текстів та інших елементів вручну, бо аналізатори в багатьох ситуаціях не здатні це зробити. Для цього рекомендуємо використовувати програму Colour Contrast Analyzer ↗
Вона безкоштовна, доступна для ОС Windows і Mac, дає можливість як зчитати кольори потрібних пікселів, так і одразу побачити коефіцієнт контрастності та критерії WCAG, які виконуються.
Букмарклети
Перевірку сайту на доступність можна значно спростити та прискорити за допомогою букмарклетів. Це невелика «розумна» закладка для вашого браузера. Замість адреси сайту в ній збережено шматочок коду (JavaScript). Коли ви відкриваєте будь-яку вебсторінку і натискаєте на таку закладку, вона не переводить вас на інший сайт, а миттєво підсвічує помилки, змінює налаштування чи показує прихований контент просто на сторінці.
Майте на увазі
Ефект від роботи букмарклета зникає, як тільки ви оновите сторінку.
Як ними користуватися?
-
Отримайте код: скопіюйте потрібний код у нас на сторінці (або попросіть написати його ШІ чи розробників).
-
Створіть закладку: додайте нову закладку на панель свого браузера, але в полі для адреси сайту (URL) вставте скопійований код.
-
Запустіть перевірку: тепер відкрийте сторінку, яку хочете протестувати, і просто натисніть на створену закладку.
Нижче ми зібрали кілька корисних букмарклетів, які точно стануть вам у пригоді.
Встановити тимчасовий маркер фокуса
Встановлює маркер фокуса у вигляді червоної рамки фокусабельним елементам. Це корисно, якщо на вебсторінці є проблеми з відображенням маркера фокуса. Це дозволить коректно протестувати її на доступність для клавіатури.
javascript:(function(){const style=document.createElement('style');style.innerHTML='a:focus,button:focus,input:focus,textarea:focus,select:focus{outline:2px solid #FF4444!important;outline-offset:2px!important;}';document.head.appendChild(style);})();
Встановити регламентовані інтервали
Встановлює текстам на вебсторінці спеціальні міжлітерні, міжслівні та інші відступи. Дозволяє перевірити, чи виконуються вимоги критерію успішності 1.4.12 WCAG.
javascript:(function(){document.body.classList.add("text-spacing");var style=document.createElement("style");style.appendChild(document.createTextNode(".text-spacing *{line-height:1.5!important;letter-spacing:.12em!important;word-spacing:.16em!important}.text-spacing p{margin-bottom:2em!important}"));document.head.appendChild(style)})();
Відключити CSS
Відключає стилі CSS на вебсторінці. Дозволяє перевірити, чи виконуються вимоги критерію успішності 1.3.2 WCAG.
javascript:(function(){document.querySelectorAll("style").forEach(e=>e.remove());document.querySelectorAll('link[rel="stylesheet"]').forEach(e=>e.remove());document.querySelectorAll("*").forEach(el=>{el.removeAttribute("style")});const reset=document.createElement("style");reset.textContent='*:not(script):not(style):not(link):not(meta):not(head):not(title){position:static!important;float:none!important;display:block!important}a,span,strong,b,i{display:inline!important}body{font-family:sans-serif!important;padding:30px!important}';document.head.appendChild(reset)})();
Встановити українську мову
Встановлює атрибут lang="uk" в елемент <head> сторінки. Це корисно, якщо на сторінці цей атрибут не вказаний чи вказаний неправильно. Це дозволить коректно протестувати її зі скринридером.
javascript:(function(){document.documentElement.setAttribute("lang","uk")})();
Показати альтернативні тексти зображень
Відображає інформацію про наявні та відсутні альтернативні тексти зображень у контейнерах, які можна перетягати курсором для зручності.
javascript:(function(){if(window.__imageAuditOverlay){window.__imageAuditOverlay.remove();window.__imageAuditOverlay=null;return}const overlay=document.createElement("div");overlay.style.position="absolute";overlay.style.left="0";overlay.style.top="0";overlay.style.width=document.documentElement.scrollWidth+"px";overlay.style.height=document.documentElement.scrollHeight+"px";overlay.style.pointerEvents="none";overlay.style.zIndex="9999999";const svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.style.position="absolute";svg.style.left="0";svg.style.top="0";svg.style.width="100%";svg.style.height="100%";overlay.appendChild(svg);document.body.appendChild(overlay);window.__imageAuditOverlay=overlay;const elements=document.querySelectorAll('img,svg[role="img"],[role="img"]');elements.forEach(el=>{const rect=el.getBoundingClientRect();const docLeft=rect.left+window.scrollX;const docTop=rect.top+window.scrollY;const alt=el.getAttribute("alt");const ariaLabel=el.getAttribute("aria-label");const labelledby=el.getAttribute("aria-labelledby");const ariaHidden=el.getAttribute("aria-hidden");const role=el.getAttribute("role");el.style.border="2px dotted #e00";let status="";let bg="";if(ariaHidden==="true"||role==="presentation"||alt===""){status="";bg="#fff3b0"}else if(alt||ariaLabel||labelledby){status="";bg="#c8f7c5"}else{status="НЕМАЄ ALT!";bg="#ffb3b3"}const label=document.createElement("div");label.textContent=status+(alt!==null?'alt="'+alt+'"':"")+(ariaLabel?'aria-label="'+ariaLabel+'"':"")+(labelledby?'aria-labelledby="'+labelledby+'"':"");label.style.position="absolute";label.style.left=docLeft+"px";label.style.top=docTop-22+"px";label.style.background=bg;label.style.color="#000";label.style.fontSize="14px";label.style.fontFamily="monospace";label.style.fontWeight="bold";label.style.padding="3px 6px";label.style.border="2px solid #e00";label.style.cursor="move";label.style.pointerEvents="auto";label.style.userSelect="none";label.style.maxWidth="500px";overlay.appendChild(label);const line=document.createElementNS("http://www.w3.org/2000/svg","line");line.setAttribute("stroke","#e00");line.setAttribute("stroke-dasharray","4 4");line.setAttribute("stroke-width","1");svg.appendChild(line);function updateLine(){const imgRect=el.getBoundingClientRect();const labelRect=label.getBoundingClientRect();const x1=labelRect.left+labelRect.width/2+window.scrollX;const y1=labelRect.bottom+window.scrollY;const x2=imgRect.left+imgRect.width/2+window.scrollX;const y2=imgRect.top+imgRect.height/2+window.scrollY;line.setAttribute("x1",x1);line.setAttribute("y1",y1);line.setAttribute("x2",x2);line.setAttribute("y2",y2)}updateLine();let dragging=false;let offsetX=0;let offsetY=0;label.addEventListener("mousedown",e=>{const rect=label.getBoundingClientRect();const labelLeft=rect.left+window.scrollX;const labelTop=rect.top+window.scrollY;offsetX=e.pageX-labelLeft;offsetY=e.pageY-labelTop;dragging=true;e.preventDefault()});document.addEventListener("mousemove",e=>{if(!dragging)return;const newLeft=e.pageX-offsetX;const newTop=e.pageY-offsetY;label.style.left=newLeft+"px";label.style.top=newTop+"px";updateLine()});document.addEventListener("mouseup",()=>{dragging=false})})})();
Перевірка заголовків
Показує, де на вебсторінці семантично вказані заголовки і який рівень вони мають. Дозволяє проаналізувати коректність застосування заголовків.
javascript:(function(){console.log('bookmarklet "headings" was called');document.querySelectorAll(".bookmarklet_notice_headings").forEach(el=>el.remove());let color_green="#186839";let bg_color_green="#97e7b9";let color_red="#71180e";let bg_color_red="#f4aaa4";function run_bm_headings(){let headings=Array.from(document.querySelectorAll("h1,h2,h3,h4,h5,h6"));let roleHeadings=Array.from(document.querySelectorAll('[role="heading"][aria-level]'));roleHeadings.forEach(roleHeading=>{let level=parseInt(roleHeading.getAttribute("aria-level"));if(!isNaN(level)&&level>=1&&level<=6){roleHeading.dataset.headingLevel=level;headings.push(roleHeading)}});if(headings.length===0){bm_headings_show_summary("warn","Немає заголовків на цій сторінці. Ймовірно, це порушення.","#825500","#fddb9b");return}let x;let messages=[];let lastHeadingLevel=0;headings.forEach((heading,index)=>{let tagName=heading.tagName??"";tagName=tagName.toLowerCase();let isNative=tagName.match(/^h\d/);let currentLevel=isNative?parseInt(heading.tagName[1]):parseInt(heading.dataset.headingLevel);let startTagSpan=document.createElement("span");startTagSpan.className="bookmarklet_notice_headings";startTagSpan.style.backgroundColor="yellow";startTagSpan.style.color="black";startTagSpan.textContent=isNative?`<${tagName}>`:`<${tagName} role="heading" aria-level="${currentLevel}">`;let endTagSpan=document.createElement("span");endTagSpan.className="bookmarklet_notice_headings";endTagSpan.style.backgroundColor="yellow";endTagSpan.style.color="black";endTagSpan.textContent=`</${tagName}>`;heading.prepend(startTagSpan);heading.append(endTagSpan);if(index===0&¤tLevel>1){x="Пропущено рівень h1.";bm_headings_add_message(heading,x,color_red,bg_color_red);messages.push(x)}if(lastHeadingLevel>0&¤tLevel>lastHeadingLevel+1){let missedLevels=[];let counter=0;for(let i=lastHeadingLevel+1;i<currentLevel;i++){missedLevels.push("h"+i);counter++}let wording=counter>1?"рівні":"рівень";x="Пропущено "+wording+" "+missedLevels.join(", ")+".";bm_headings_add_message(heading,x,color_red,bg_color_red);messages.push(x)}lastHeadingLevel=currentLevel});let texts="";if(messages.length>0){texts="Список виявлених проблем:";messages.forEach(message=>{texts+="<br><br>"+message});bm_headings_show_summary("bad",texts,color_red,bg_color_red)}else{texts="Заголовки є, проблем не виявлено<br>(але потрібно перевірити на коректність і логічність).";bm_headings_show_summary("good",texts,color_green,bg_color_green)}}function bm_headings_add_message(element,text,color,bgColor){let message=document.createElement("div");message.className="bookmarklet_notice_headings";message.textContent="❌ "+text;message.style.color=color;message.style.backgroundColor=bgColor;message.style.padding="8px";message.style.fontWeight="bold";element.parentNode.insertBefore(message,element)}function bm_headings_show_summary(status,text,color="#000",bg_color="#eee"){let statuses={good:"✔️",bad:"❌",warn:"⚠️"};status=statuses[status]??statuses.warn;let msg=document.createElement("div");msg.className="bookmarklet_notice_headings";msg.style.position="fixed";msg.style.top="0";msg.style.right="0";msg.style.fontWeight="bold";msg.style.padding="10px";msg.style.zIndex="9999";msg.style.color=color;msg.style.backgroundColor=bg_color;msg.innerHTML='<div style="display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start"><div>'+status+'</div><div style="margin-left:10px">'+text+'</div><div style="margin-left:10px"><span role="button" tabindex="0" aria-label="Видалити зі сторінки наслідки застосування букмарклета Заголовки" onclick="document.querySelectorAll(\'.bookmarklet_notice_headings\').forEach(el=>el.remove());" style="cursor:pointer">X</span></div></div>';document.body.insertBefore(msg,document.body.firstChild)}setTimeout(function(){run_bm_headings()},200)})();