이 글은 Pogee의 편집 기획으로, 생성형 AI를 사용하여 작성되었습니다. HTML, 이미지 경로, 설명문은 독립된 가상의 교재입니다. Pogee의 실제 화면, 내부 구현, 대화 로그는 사용하지 않았습니다. 게재 코드는 로컬에서 실행 확인했습니다.
이미지가 나열되는 피드에서는 시각적인 내용뿐만 아니라, 이미지가 전달하는 내용을 텍스트로도 받을 수 있는지 확인할 필요가 있습니다. 첫 번째 정리 단계로, HTML에 있는 img 요소를 열거하고, alt 속성이 '없음', '비어있거나 공백만 있음', '문자가 있음' 중 어느 경우인지 분류해봅니다.
이것은 웹 접근성 적합성을 판정하는 도구는 아닙니다. 장식용 이미지라면 빈 alt가 적절할 수 있으며, 문자가 있더라도 이미지가 의미를 전달하고 있다고 단정하기 어렵습니다. 기계는 확인 후보를 추출하고, 이미지의 역할과 맥락은 사람이 확인한다는 역할 분담을 합니다.
이번에는 Node.js와 HTML 파서인 parse5를 사용합니다. 속성명의 대소문자, 줄 바꿈, 문자 참조, 주석이나 script 내부의 문자열을 HTML로 처리하기 위함입니다. 브라우저는 실행하지 않고, 직접 준비한 로컬 HTML 파일만 읽습니다. 외부 사이트 접근이나 이미지 가져오기는 수행하지 않습니다.
[IMG:N]
실행 환경은 Node.js v25.2.1, parse5 8.0.0입니다. 비어있는 작업 디렉토리에서 다음을 실행합니다. --save-exact로 의존성을 직접 고정하고, 생성된 package-lock.json도 저장합니다. 동일한 의존성 해결을 재현할 때는 해당 파일과 package.json을 사용하여 npm ci를 실행합니다.
다음 내용을 feed.html로 저장합니다. station.png 등은 속성 검사용 가상 경로입니다. 이미지 파일 배포나 로딩이 없으며, alt 내용이 실제 이미지와 일치하는지 테스트한 결과도 아닙니다. line은 이 파일 내에서 img의 시작 태그가 시작되는 줄 번호입니다.
<!doctype html>
<html lang="ja">
<meta charset="utf-8">
...
첫 번째는 비어있지 않은 설명, 두 번째는 장식용으로 가정된 빈 문자열, 세 번째는 alt 누락, 네 번째는 공백만 있습니다. 빈 문자열과 공백만 있는 경우는 같은 확인 그룹에 묶지만, 원래 값은 출력에 남깁니다. 네 번째의 srcset도 문자열로 기록할 뿐, 후보 URL의 구문이나 선택 결과를 검증하지 않습니다.
다음 내용을 동일 디렉토리의 check-image-alt.mjs에 저장합니다. .mjs이므로 ES Modules로 실행할 수 있습니다. parse의 sourceCodeLocationInfo를 활성화하고, HTML 이름 공간의 img만 처리합니다.
import { readFile } from "node:fs/promises";
import { parse } from "parse5";
function* elements(node) {
...
출력은 첫 번째 줄이 집계이고, 그 이후가 이미지별 JSON입니다. JSON.stringify를 사용하므로 속성 값에 줄 바꿈이나 탭이 있어도 한 레코드의 구분을 깨지 않습니다. alt가 존재하지 않으면 null, 빈 문자열이면 ""을 남기므로, 누락과 공백을 구분할 수 있습니다. src와 srcset은 원문 속성값이며, 절대 URL로 해결하거나 이미지 도달 확인을 하지 않았습니다.
종료 코드는 이 교재의 확인 규칙입니다. MISSING_ALT가 1건 이상이면 1, 아니면 0, 인자 부족이나 파일 로딩 실패 시 2입니다. 1은 확인이 필요한 후보를 발견했다는 것만을 의미하고, 0은 누락된 것이 없다는 것만을 의미합니다. HTML 표준이나 WCAG 전체 합격 여부로 대체될 수 없습니다.
node --version
node check-image-alt.mjs feed.html
v25.2.1
{"images":4,"missing":1,"empty":2,"text":1}
{"image":1,"line":8,"status":"TEXT_ALT_REVIEW","alt":"雨の駅で赤い傘を持つ人物","src":"station.png","srcset":null}
...
이 실행의 종료 코드는 1입니다. 4장 중, alt 누락이 1개, 비어 있거나 공백만 있는 것이 2개, 비공백 문자가 1개로 확인되었습니다. line 10의 이미지에 대해서는, 이미지가 가진 정보나 링크 목적지 등을 확인한 후에 수정할 것입니다. 누락을 없애기 위해 기계적으로 alt=""를 추가하는 방법으로는 필요한 정보까지 지워버릴 수 있습니다.
위의 4장을 포함한 입력 외에도, 다음 독립적인 합성 입력을 실제로 실행했습니다. 표의 '건수'는 실행된 입력 파일 또는 인자 조건의 개수입니다. 공개 사이트의 검사 건수, Pogee의 이미지 건수, 사용자 평가는 아닙니다.
| 입력 종류 | 건수 | 확인 결과 |
|---|
| 본문의 4장 HTML | 1 | 4장, 누락 1・공백 2・비공백 1, 종료 1 |
| ... | | |
| 예를 들어 이미지가 없는 HTML에서는 다음 한 줄만 나왔습니다. 종료 코드는 0이지만, '이미지가 적절함'이라는 결과는 아닙니다. JavaScript로 이미지를 추가하는 페이지의 원본 HTML 등, 애초에 기대하는 img가 들어있지 않을 가능성을 먼저 확인합니다. | | |
{"images":0,"missing":0,"empty":0,"text":0}
parse5는 HTML을 분석할 뿐 JavaScript를 실행하지 않습니다. 이 검사는 childNodes만을 따라가기 때문에, template.content의 미전개 이미지도 대상에서 제외됩니다. 주석이나 script 문자열 속의 가상 태그를 이미지로 오인하지 않는 것은 별도의 입력으로 확인하고 있습니다. HTML이 부정확해도 파서가 보정하는 경우가 있으므로, HTML 유효성 검사기로도 사용하지 않습니다.
W3C WAI의 alt 결정 트리는, 이미지가 문맥에 의미를 더하는지, 장식인지, 근처 텍스트와 중복되는지에 따라 작성 방식이 달라집니다. 정보를 가진 사진이라면, 그 자리에서 필요한 의미를 짧게 전달합니다. 링크나 조작의 일부라면, 대상이나 기능까지 포함하여 생각합니다. 도표의 정보량이 많다면, 짧은 alt에만 담지 않고 본문 쪽 설명도 검토합니다.
EMPTY_ALT_REVIEW는 '비어 있으니 실패'가 아닙니다. 장식으로서 비어 있는 것이 적절한지, 정보를 담당하는 이미지인데 설명이 빠지지 않았는지 확인하기 위한 표시입니다. TEXT_ALT_REVIEW 역시 '설명 완료되어 성공'이 아니며, 파일명만 기술되었는지, 근처 문장과 중복되는지, 이미지와 불일치가 없는지를 봅니다.
이 코드는 CSS의 배경 이미지, SVG의 image 요소, iframe 내의 별도 문서, Shadow DOM, JavaScript 생성 후의 DOM, 실제 이미지 표시, 스크린 리더의 읽어주기를 확인하지 않습니다. aria-label이나 role 등을 포함한 접근 가능한 이름 계산도 대상에서 제외합니다. 권한이 있는 실 페이지로 이동할 때는, 표시된 이후 상태나 조작을 다른 공정에서 확인합니다.
공개 피드라고 해서, 제3자의 페이지를 일괄적으로 가져올 필요는 없습니다. 먼저 직접 만든 템플릿이나 허가된 HTML로부터 후보를 추출하고, 리뷰에서 이미지와 본문을 함께 확인하는 사용법이 출발점이 됩니다. 본고의 결과는 이 가상의 교재와 실행 환경에 한정됩니다.
아래 공식 공개 자료를 2026년 10월 18일에 확인했습니다. parse5의 API는 HTML 문자열의 분석, MDN과 WAI는 alt의 용도와 문맥 판단을 참조하고 있습니다.