마이크로 인터랙션에 관한 글에서 저는 transform과 opacity가 컴포지터 스레드에서 애니메이션되므로, 아무리 무거운 페이지라도 버튼 애니메이션이 끊겨서는 안 된다고 썼습니다. 이는 여전히 사실입니다 – 다만 그 글이 침묵했던 한 가지 단서가 있습니다. 메인 스레드가 긴 JS 작업으로 막혀 있다면, 애니메이션은 시작할 기회조차 얻지 못할 수 있습니다. 클릭 핸들러 자체가 대기열에서 기다리고 있기 때문입니다. INP는 정확히 이 틈을 측정하는 지표이며, scheduler.yield()는 그 틈을 실제로 메울 수 있는 몇 안 되는 방법 중 하나입니다.
댓글 천 개짜리 목록이 느리게 렌더링되어 react-window를 꺼내 듭니다 – 그런데 부드러운 스크롤을 얻는 대가로 Ctrl+F, 페이지 인쇄, 그리고 스크린 리더 탐색 일부를 잃게 됩니다. 화면 밖 요소들이 DOM에서 물리적으로 사라져버리기 때문입니다. content-visibility는 같은 문제를 다른 방식으로 풉니다 – 요소는 DOM에 그대로 남아 있고, 브라우저는 화면 근처에 오기 전까지 비용이 큰 레이아웃과 페인트 작업만 건너뜁니다. 그리고 놀랍게도, 그 안의 텍스트를 검색할 때는 일시적으로 다시 드러내 줄 수도 있습니다.
접근성 글에서 다룬, display:none으로 감췄지만 접근성 트리에는 여전히 남아 있던 모달은 div로 처음부터 직접 만든 모달에서 비롯된 실수의 한 예였습니다. 진짜 질문은 애초에 왜 그것을 처음부터 만들어야 했는가입니다. 네이티브 <dialog>와 popover 속성이 공짜로 제공하는 것 – 톱 레이어, 포커스 트랩, light dismiss – 이 무엇인지, 그리고 이 두 메커니즘이 서로 헷갈리면 곧바로 접근성이 떨어지는 인터페이스로 이어질 만큼 다른 지점이 어디인지 살펴봅니다.
'좋아요' 버튼은 서버가 응답하기도 전에 즉시 반응하며, 하트가 채워지고 카운터가 올라갑니다. 이는 마이크로 인터랙션 글에서 다룬 속도의 착시가 아니라, 그보다 한 걸음 더 나아간 것입니다. 인터페이스가 아직 존재하지 않는 상태를 보여주며, 그것이 곧 실현될 것이라고 가정하는 것입니다. 이를 안전하게 만드는 법 – 가정이 틀렸을 때 그 거짓말에서 실제로 되돌아 나오는 방법 – 그리고 수동 setState와 catch가 useOptimistic이 제공하는 것보다 왜 열등한 버전인지 살펴봅니다.
유틸리티 클래스 .mt-4는 나중에 추가되었으니 논리적으로는 이겨야 할 것 같은데도 .card .card__header .card__title 규칙에 집니다. 이는 우연이 아니라 특이성이 설계된 대로 정확히 작동하고 있는 것입니다. @layer는 특이성과 함께가 아니라 그보다 앞서 작동하는, 충돌 해결의 완전히 새로운 축을 도입합니다 – 그리고 어찌나 직관에 어긋나는지, 웹상의 일부 문서조차 잘못 설명하는 함정이 하나 있습니다.
'use server'는 API 라우트로의 fetch를 위한 문법적 설탕처럼 보입니다 – 그리고 바로 그 이유로 대부분의 구현이 이를 그냥 함수 호출처럼 다룹니다. 이는 구체적인 결과를 초래하는 실수입니다. 'use server'가 붙은 모든 함수는 네트워크상의 공개 엔드포인트가 되며, 이 메커니즘 위에 지어진 폼은 JavaScript가 로드되기도 전에 작동합니다. 이 지시어 아래에서 실제로 무슨 일이 일어나는지, 그리고 문서만 봐서는 한눈에 보이지 않는 함정이 어디에 있는지 살펴봅니다.
폼 필드는 내부의 input이 유효하지 않을 때 빨간색으로 강조되어야 합니다. 간단해 보이는 일입니다 – 다만 CSS는 25년 동안 요소에게 그 내부에서 무슨 일이 일어나고 있는지 물어볼 방법이 없었고, 오직 그 반대 방향만 가능했습니다. :has()가 이 방향을 어떻게 뒤집는지, 일반적인 결합자와 어떻게 다른지, 그리고 이 새로운 힘이 실제로 성능에 어떤 대가를 치르게 하는지 살펴봅니다.
같은 상품 카드가 그리드에서는 근사하게 보이지만, 미디어 쿼리를 정성껏 짜놓았음에도 좁은 사이드바에서는 무너집니다. 문제는 코드에 있는 게 아니라 미디어 쿼리가 던지는 질문 자체에 있습니다 – 화면의 너비를 묻는 것이지, 컴포넌트가 실제로 받은 공간을 묻는 게 아니라는 것이죠. 컨테이너 쿼리가 이 질문을 원래 있어야 할 자리로 옮기는 방법과, 요소가 '쿼리 컨테이너'가 될 때 내부에서 실제로 무슨 일이 벌어지는지 살펴봅니다.
CSS Houdini는 하나의 기술이 아니라, 성숙도가 저마다 크게 다른 여러 명세의 모음입니다. 오늘날 실제 프로덕션에 사용할 수 있는 부분은 어디인지, @property와 paint worklet이 실제로 어떻게 작동하는지, 그리고 나머지가 왜 아직 실험 단계에 머물러 있는지 확인해 보세요.
같은 상품, 같은 서버 응답 시간을 가진 두 스토어인데도 한쪽이 더 빠르고 신뢰할 수 있게 느껴지는 이유는 마이크로 인터랙션에 있습니다 – 사용자가 화면 위의 것을 믿을지 말지를 결정짓는 수백 밀리초짜리 애니메이션입니다. 트리거/피드백 모델, 브라우저 렌더링 엔진 내부에서 실제로 일어나는 일, 그리고 prefers-reduced-motion까지 원리부터 하나씩 짚어봅니다.