• 개발
  • 9th September 2026
화면 밖 목록의 렌더를 건너뛴다 — content-visibility 로 레이아웃 속도를 비약적으로 끌어올리기

목록 화면에 항목이 수천 개 있다. 사용자 화면에 실제로 보이는 것은 열 개쯤이다. 그런데 브라우저는 보이지 않는 나머지까지 전부 레이아웃하고 페인트한다. 각 항목의 높이를 계산하고, 문서 전체 높이를 구하고, 스크롤바 길이를 정한다. 이 낭비를 줄이는 방법은 오랫동안 자바스크립트였다. 화면에 보이는 만큼만 DOM에 넣고 스크롤에 따라 갈아 끼우는 가상 스크롤이다. 잘 동작하지만 직접 구현하면 스크롤 위치 복원, 키...

Read More
  • 개발
  • 9th September 2026
PHP 8.6은 세션 쿠키에 HttpOnly·SameSite=Lax를 붙인다 — 11월 19일 전에 확인할 세 가지

PHP 8.6이 2026년 11월 19일에 나온다. 세션 확장의 ini 기본값 셋이 바뀐다. 코드를 한 줄도 고치지 않아도 세션 쿠키에 붙는 속성이 달라진다. 같은 코드에 같은 요청을 보내고 응답 헤더만 비교하면 이렇다. # PHP 8.5.4 Set-Cookie: PHPSESSID=75586de12bb15eb5…; path=/ # PHP 8.6.0beta2 Set-Cookie: PHPSESSID=d6522d741bd160b6…; path=/; HttpOnly; SameSite=Lax 바뀌는 값은 셋이다. 설정 8.5까지 8.6부터 막는 것 sessio...

Read More
  • 개발
  • 8th September 2026
안에서 밖으로 읽던 함수 중첩을, 위에서 아래로 — PHP 8.5 파이프 연산자 |>

입력값을 다듬는 코드는 대개 이런 모양이 된다. $amount = intval(preg_replace('/[^0-9]/', '', str_replace(',', '', trim($raw)))); 실행은 trim부터다. 그 다음 str_replace, preg_replace, intval 순서로 간다. 그런데 눈은 정반대로 움직인다. 왼쪽 끝의 intval을 먼저 만나고, 괄호를 따라 안쪽으로 파고들어 trim에 닿은 다음, 거기서 다시 밖으로 나오면서 순서를 되짚어야 한다. 그래서 보통은 임시 변수로 푼다. $trim...

Read More
  • 개발
  • 8th September 2026
미디어 쿼리로는 안 되던 것 — @container 로 부모가 정한 값에 반응하기

같은 카드 부품이 본문에도 들어가고, 좁은 사이드바에도 들어가고, 어두운 배너 안에도 들어간다. 자리마다 조금씩 달라야 한다. 사이드바에서는 설명을 감추고, 배너 안에서는 글자를 밝게. 화면 크기로 갈라 볼까 싶지만 그건 답이 아니다. 미디어 쿼리는 화면만 본다. 넓은 데스크톱 화면에서도 사이드바는 여전히 좁고, 같은 화면 안에서 본문에 있는 카드와 사이드바에 있는 카드는 구분되지 않는다. 부품이 알아야 하는 것...

Read More
  • 개발
  • 7th September 2026
text-indent: hanging / each-line — padding-left + 음수 text-indent 트릭을 걷어내기

참고문헌 목록, 용어 정의, 시, 대본, 주소. 첫 줄은 왼쪽 끝에 붙고 둘째 줄부터 들여쓰는 내어쓰기(hanging indent)가 필요한 자리는 많다. 그리고 CSS에는 오랫동안 이걸 바로 말하는 문법이 없었다. 대신 모두가 같은 트릭을 썼다. .ref { padding-left: 2em; text-indent: -2em; } 블록 전체를 2em 밀어 넣고, 첫 줄만 2em 도로 당긴다. 결과는 내어쓰기처럼 보인다. 20년 넘게 쓰인 트릭이고 지금도 검색하면 이게 나온다. ...

Read More
  • 개발
  • 7th September 2026
PHP 8.5 URI 확장 — parse_url()을 손으로 꿰매던 origin 비교와 상대경로 해석을 표준으로

PHP로 웹을 만들다 보면 이런 함수를 한 번쯤 짜게 된다. function sameOrigin(string $a, string $b): bool { $pa = parse_url($a); $pb = parse_url($b); return strtolower($pa['scheme'] ?? '') === strtolower($pb['scheme'] ?? '') strtolower($pa['host'] ?? '') === strtolower($pb['host'] ?? '') ($pa['port'] ?? null) === ($pb['port'] ?? null); } 리다이렉트 대상이 우리 사이트인지, 웹훅 URL이 허용된 호스트인...

Read More
  • 개발
  • 4th September 2026
영상 200개에 자막 붙이기 — whisper.cpp로 WebVTT 뽑고, 그 파일 하나로 자막과 대본까지

홈페이지에 올라간 영상이 200개를 넘는데 자막이 붙은 것은 하나도 없었다. 홍보영상, 뉴스에 나온 장면, 교가까지. 영상 아래에 내용을 텍스트로 적어둔 것은 있었다. 그런데 접근성 검수에서 그것으로는 안 된다고 걸렸고, 영상 하나하나에 사람이 자막을 받아 적을 수는 없었다. 결국 음성 인식으로 초안을 뽑고 손으로 다듬어 전부 붙였다. 그 과정에서 알게 된 것들을 정리한다. 자막 파일을 만드는 쪽과 웹에 붙이는 쪽 양...

Read More
  • 개발
  • 4th September 2026
CSS 단위 총정리 — px·rem·lh·dvh·cqi, 마흔 개 단위를 기준 다섯 개로 읽기

CSS 단위는 한동안 px, em, %, 인쇄용 pt 정도였다. 지금은 길이 단위만 세어도 마흔 개에 가깝다. rem이 들어오고, 뷰포트 단위가 들어오고, 그 뷰포트 단위가 다시 셋으로 갈라지고, 컨테이너 단위가 들어오고, 글꼴 단위마다 r 붙은 짝이 생겼다. 이걸 전부 외울 필요는 없다. 단위가 늘어난 방향은 하나다. "무엇을 기준으로 재는가"의 선택지가 늘어난 것이다. 기준을 알면 단위는 저절로 나온다. 단위는 기준으로 나뉜다 모...

Read More
  • 개발
  • 4th September 2026
field-sizing: content — textarea 자동 높이 스크립트를 CSS 한 줄로 걷어내기

게시판 글쓰기 화면의 textarea는 늘 두 줄 높이로 시작한다. 세 줄째부터 스크롤바가 생기고, 사용자는 자기가 쓴 글의 윗부분을 못 보면서 계속 쓴다. 그래서 어느 프로젝트에나 이런 코드가 하나씩 있다. textarea.addEventListener('input', function () { this.style.height = 'auto'; this.style.height = this.scrollHeight + 'px'; }); 키를 누를 때마다 높이를 0으로 눌렀다가 scrollHeight만큼 다시 편다. 동작은 하지만...

Read More
  • 개발
  • 28th August 2026
폰에서 번호 페이징(1 2 3 … 50)을 버리고 가로 스크롤 한 줄로 바꾼 이유

목록 화면 아래에는 대개 이런 줄이 붙어 있다. « ‹ 6 7 8 9 › ». 데스크톱에서는 이 줄이 아무 문제를 일으키지 않는다. 폭이 900px쯤 되니 번호 아홉 개에 이동 버튼 넷을 붙여도 여유롭다. 폰에서 같은 줄을 열면 사정이 달라진다. 그리고 대부분의 프로젝트가 같은 방식으로 이 문제를 처리한다 — 번호 개수를 줄인다. 데스크톱은 9개, 모바일은 4개. 이 타협을 오래 쓰다가 결국 버렸다. 번호를 줄이는 대신, 넘치면 가로로 ...

Read More