ARCHIVE
아카이브
기존에 공개한 글을 원래 주소 그대로 보관합니다.
과거의 글에는 작성 당시의 기술과 관점이 담겨 있습니다.
356개 글 · 2 / 12 페이지
· KO
표본 26장이 놓친 위반 3종: WCAG-EM 2.0을 1,342장에 적용한 기록
W3C가 7월 23일 WCAG-EM 2.0을 Group Note로 발행했다. 문서의 표본 추출 절차대로 26장을 뽑고, 같은 빌드의 1,342장 전체를 axe-core로 훑어 대조했다. 표본은 위반 4종 중 1종만 잡았고, 무작위 표본의 새 발견 확률은 0.29%였다.
· KO
제목을 선언하는 일곱 곳 중 여섯 곳만 내가 썼다: 앵커 텍스트 18,296개 실측
한 페이지의 제목은 title·h1·og:title·headline·RSS 등 여섯 곳에서 선언된다. 1,296편 전부 일치했다. 문제는 일곱 번째 채널이었다. 내부 링크 18,296개 중 목표 글 제목과 일치하는 앵커 텍스트는 0.7%뿐이었고, 원인은 카드를 감싼 링크 하나였다.
· KO
내부 링크 46,382개 중 24,948개가 301로 튕기고 있었다
접근성 지표를 재려고 만든 스크립트가 URL 버그를 잡아냈다. 빌드된 HTML 1,334장의 내부 링크를 전수 조사하니 절반이 넘는 24,948개가 트레일링 슬래시 없는 주소, 즉 301 리다이렉트를 거치는 주소를 가리키고 있었다. 원인과 네 단계의 수정, 그리고 0으로 만든 기록.
· KO
언어별 아카이브 네 장을 지웠더니 296편이 도달 불가가 됐다: 크롤 깊이 실측
관련 글이 평균 8개씩 걸린 사이트의 내부 링크를 도달성 기준으로 다시 세어 봤다. 빌드된 HTML 1,330장을 너비 우선 탐색하니 글 1,288편 중 1,276편이 깊이 2였다. 그런데 언어별 목록 페이지 네 장을 링크 그래프에서 빼자 296편이 홈에서 닿지 않았다.
· KO
div 그리드로 만든 표가 조용히 잃는 것: 접근성 트리와 텍스트 추출 동시 실측
같은 영업시간 표를 네 가지 마크업으로 만들어 axe-core와 추출기 다섯 벌에 통과시켰다. axe는 네 개 모두 위반 0건을 줬지만, HTML을 텍스트로 바꾸는 순간 7행이 통째로 사라지는 마크업이 셋이었다. role="table"이 못 구하는 층을 실측 로그로 정리했다.
· KO
prerender에서 LCP가 6.2초로 찍힌 이유 — activationStart를 뺀 RUM만 맞다
Speculation Rules로 페이지를 미리 렌더링하면 LCP 원본값에 사용자 대기 시간이 통째로 들어간다. Chrome 150에서 6244ms와 103.5ms의 간극을 실측하고, activationStart로 보정해야 할 지점을 RUM 계측 코드 기준으로 하나씩 정리했다.
· KO
모델 버전을 올릴 때마다 인젝션 테스트를 다시 돌리는 이유: 게이트를 직접 짜봤다
LLM 파이프라인에 프롬프트 인젝션 회귀 스위트를 직접 돌렸다. 순진한 키워드 가드는 11건 중 2건, 구조적 가드는 11건 전부를 잡았고, 내가 저지른 리팩터링이 떨어뜨린 탐지까지 게이트가 집어냈다. 모델 버전을 올릴 때마다 다시 돌려야 하는 이유를 실측으로 정리했다.
· KO
WebMCP가 오리진 트라이얼에 들어왔다 — provideContext는 왜 반년 만에 사라졌나
WebMCP가 Chrome 149 오리진 트라이얼로 배포됐지만 2월 API는 이미 바뀌었다. navigator.modelContext는 document.modelContext로 옮겨졌고 provideContext는 보안 문제로 사라졌다. 지금 등록해야 할 툴 형태를 정리했다.
· KO
FAQPage 리치 결과는 끝났다. 그런데 Q&A 마크업은 지우지 마라
Google이 2026년 5월 7일 FAQ 리치 결과를 완전히 종료했다. 오프라인 검증기로 FAQPage JSON-LD를 실측하면 스키마는 통과하지만 리치 결과는 DEPRECATED다. 검증 통과와 노출이 갈라진 지금 코드와 콘텐츠를 어떻게 바꿀지 공식 문서로 정리했다.
· KO
공식은 "WebSocket이 bfcache를 막지 않는다"고 했다 — 다시 재보니 세 번 다 막혔다
Chrome 149가 WebSocket의 bfcache 차단을 풀었다고 발표했다. Chrome 150 세 환경에서 다시 재보니 notRestoredReasons는 여전히 websocket을 돌려줬다. 릴리스 노트와 실측이 갈리는 지점을 재현 스크립트와 측정 로그까지 함께 기록했다.
· KO
aria-modal="true"는 아무것도 막지 않았다 — 모달 포커스 이탈 실측과 inert
role="dialog"에 aria-modal="true"까지 붙인 모달에서 Tab을 세 번 누르자 포커스가 오버레이 뒤로 빠져나갔다. axe는 위반 0건. 같은 마크업을 aria-hidden, inert로 바꿔가며 키보드 포커스가 실제로 어디에 떨어지는지 기록했다.
· KO
opens: "eleven"은 검증기도 통과한다 — 음식점 영업시간 JSON-LD 3계층 실측
직접 운영하는 음식점 추천 PWA에 Restaurant 구조화 데이터를 넣으면서 요일별 평문 영업시간 문자열을 openingHoursSpecification으로 변환하고, 같은 결함 세 개를 타입체크·스키마 검증기·런타임 게이트에 차례로 넣어 어느 계층이 무엇을 잡는지 측정했다.
· KO
beforeunload는 통과했고 unload는 막혔다: bfcache 실측 6판
뒤로 가기가 즉시 열리는지는 취향이 아니라 측정 대상이다. 차단 조건을 하나씩 심은 페이지 여섯 개에 back 내비게이션을 걸어 pageshow.persisted와 notRestoredReasons를 받아냈다. unload는 막혔고 beforeunload와 no-store는 통과했다.
· KO
내 피드에 네 언어 1,248건이 섞여 있었고, 언어 표시는 하나도 없었다
W3C가 공개한 문자열 언어·방향 메타데이터 초안을 기준으로 4개 언어 블로그를 감사했다. 통합 RSS 1,248건이 언어 표시 없이 나갔고 dir="auto" 휴리스틱은 14건 중 4건을 틀렸다. dc:language 수정 코드와 회귀를 막는 빌드 게이트까지 정리한다.
· KO
WCAG 2.2 최소 타깃 크기, 초록불 92점 뒤에 숨은 AA 실패
손끝이 빗나가는 22×22 버튼에 Lighthouse는 접근성 92점을 줬다. WCAG 2.2 SC 2.5.8(최소 24×24)을 샌드박스에 심어 재보니 자동 도구는 크기 위반만 잡고 예외 조항은 사람에게 넘겼다. 스페이싱 예외 계산과 CSS 수정을 실측 로그로 정리한다.
· KO
AI Overview가 내 페이지를 인용할지 정하는 meta 한 줄 — robots 스니펫 지시자 실측
nosnippet 한 줄은 이제 검색 스니펫만 끄지 않는다. Google 공식 문서는 이 지시자가 AI Overview·AI Mode의 인용 입력까지 막는다고 못박았다. 두 페이지를 만들어 파서로 max-snippet·data-nosnippet의 실제 효과를 다시 재봤다.
· KO
CSS 한 줄로 강제 레이아웃 27.3ms를 1.8ms로 — content-visibility 실측
같은 HTML, 같은 바이트인데 CSS 한 줄만 넣었더니 강제 레이아웃이 27.3ms에서 1.8ms로 줄었다. 400개 섹션 페이지 두 벌을 Chrome 트레이스로 재고, content-visibility: auto의 절감분과 contain-intrinsic-size 함정까지 정리한다.
· KO
클릭 한 번에 264ms — 같은 일을 쪼갰더니 56ms, INP 실측기
INP는 2024년 FID를 대체한 Core Web Vitals 응답성 지표다. 같은 220ms 작업을 통짜로 돌릴 때와 scheduler.yield로 쪼갤 때를 Event Timing API로 측정했다. 264ms(개선 필요)가 56ms(양호)로 떨어지는 과정을 코드와 로그로 기록한다.
· KO
버튼을 누르려는 순간 화면이 밀렸다 — CLS 0.559를 0.014로 내린 실측 기록
로딩 중 레이아웃이 밀리는 건 취향 문제가 아니라 측정 가능한 지표다. 같은 페이지를 두 가지로 만들어 layout-shift PerformanceObserver로 CLS를 재고, 이미지 크기 예약과 슬롯 확보만으로 0.559(POOR)를 0.014(GOOD)까지 내린 기록이다.
· KO
히어로 이미지는 117KB였는데 LCP는 1.2초 — 브라우저가 이미지를 늦게 찾는 진짜 이유
LCP가 느린 건 이미지가 무거워서가 아니라 브라우저가 언제 그 이미지를 발견하느냐의 문제다. CSS 배경 이미지가 프리로드 스캐너에 안 보이는 현상을 Chrome DevTools로 실측하고 fetchpriority로 LCP 1247ms를 109ms까지 내린 실전 기록.
· KO
구조화 데이터를 배포 전에 잡아라 — JSON-LD를 CI에서 자동 검증하는 법
JSON-LD 파서가 통과시켜도 검색엔진은 못 읽는 마크업이 있다. schema.org의 @vocab 때문에 오타와 대소문자 오류가 정상 JSON-LD로 조용히 확장된다. 60줄짜리 스키마 인지 검증기를 GitHub Actions CI에 넣어 배포 전에 자동으로 잡은 실측 기록이다.
· KO
접근성 자동 검사가 초록불을 줘도 남아 있는 네 가지 장벽
체크아웃 페이지 하나에 WCAG 장벽 여덟 개를 일부러 심고 axe-core로 돌렸다. 규칙형 위반 넷은 잡혔지만, 사람의 판단이 필요한 넷은 초록불 뒤에 그대로 남았다. 무엇을 자동화가 끝까지 못 보는지, 그 자리를 메우는 수동 리뷰 체크리스트를 실측 로그와 함께 정리했다.
· KO
JSON-LD vs Microdata vs RDFa — 구조화 데이터 문법, 무엇을 언제 쓸까 (실측 비교)
같은 Product 엔티티를 세 문법으로 각각 짜서 파서에 넣고 바이트 수와 취약성을 실측했다. Google은 셋 다 동등하게 취급한다. 그렇다면 JSON-LD를 권하는 진짜 이유는 순위가 아니라 재설계에서 살아남는 결합도였다. 공식 문서와 재현 로그로 정리한 실전 선택 기준.
· KO
접근성 이름이 틀리면 음성 제어도 AI 에이전트도 버튼을 못 누른다
버튼에 aria-label을 붙였는데 접근성 트리는 화면에 없는 글자를 읽는다. WCAG 2.5.3 Label in Name 위반을 샌드박스에서 재현해 확인하고, Lighthouse 13.3.0의 Agentic Browsing 점수가 0점에서 100점으로 바뀌는 과정을 실측했다.
· KO
AI 크롤러는 당신의 자바스크립트를 실행하지 않는다
GPTBot·ClaudeBot 같은 AI 크롤러는 자바스크립트를 실행하지 않아, CSR로만 렌더링한 페이지는 AI 검색과 인용에서 통째로 사라진다. 그 원인을 curl 요청으로 직접 재현해 확인하고, 서버사이드 렌더링과 프리렌더링으로 콘텐츠를 다시 노출시키는 구체적 방법까지 정리했다.
· KO
sitemap.xml에서 구글이 실제로 읽는 건 lastmod 하나다
priority 1.0에 changefreq always를 붙여도 구글은 다 버린다. 공식 문서가 쓰는 필드는 lastmod 하나뿐이고, 그마저 검증 가능하게 정확할 때만 쓴다. 세 종류의 sitemap을 공식 XSD로 직접 돌려 무엇이 통과하고 무엇이 조용히 무시되는지 실측했다.
· KO
axe-core를 CI에 넣으면 color-contrast만 조용히 사라지는 이유
AI가 만든 예약 위젯을 jsdom과 실제 브라우저에서 axe-core로 돌려봤다. 구조적 위반 4개는 브라우저 없이 잡혔지만 color-contrast만 jsdom에서 incomplete로 빠졌다. CI를 2단으로 짜야 커버리지 구멍이 안 생기는지 실측 로그와 함께 정리했다.
· KO
기술 SEO 감사를 닷새간 돌려봤다 — 고친 다섯 항목보다 중요했던 건 게이트였다
4개 언어 블로그를 닷새간 실측 감사했다. relatedPosts 404 12개, hreflang 파손 4쌍, 렌더 블로킹 405KB, 번역 드리프트 21건, JSON-LD 조각 7개를 다 고쳤다. 진짜 성과는 이 수정들이 다시 되돌아오지 못하게 막은 빌드 게이트였다.
· KO
JSON-LD를 @graph 하나로 묶기 — 흩어진 구조화 데이터를 검색·AI가 읽는 엔티티 모델로
내 페이지의 JSON-LD를 검증기에 넣었더니 세 조각으로 흩어져 있었다. @id 참조로 Organization·WebSite·Article을 하나의 @graph로 잇고 jsonld로 연결성을 실측했다. 3개 컴포넌트가 1개로 합쳐지는 과정과 Google이 보장하지 않는 지점까지.
· KO
hreflang은 양방향이어야 한다 — 내 4개 언어 블로그를 직접 감사해 찾은 홈페이지 버그
30줄짜리 검사기를 내 사이트의 빌드 결과물에 직접 돌렸다. 블로그 글 248개의 hreflang 클러스터는 전부 통과했는데 홈페이지 하나가 걸렸다. Google 공식 리시프로시티 규칙, 실측 로그, 세 가지 구현 방법 비교, 그리고 개발자가 바로 적용할 수정 코드까지 정리했다.