Skip to content

CSS 순서 의존을 소유 화면으로 통합 — U07 잔여 스타일 정리 (2026-09-10)

  • 기간: 2026-09-10, 1세션. 오너: “바벨릭 #1532 진행해줘. 나한테 물어보지 말고 phase 끝까지 완주”.
  • 랜딩: 앱 PR #1549 / 4a642ad39474ae7782ad9c34b2be7eb6aa3a00a2 (2026-09-10 20:36 KST), 목적 release/v0.18.0. 문서 저장소에서 독립 게시. 마이그레이션·Edge·staging/Production 배포 없음.
  • 설계서: 별도 artifact 없음. #1532 Phase 계획, Phase 4 채택 계획.
  • 정본·계약: 공통 시각 기반 U07, G05 UI 장부.
  • 도구: 앱의 기존 PostCSS/Vite/Playwright와 dead CSS gate 사용. 소스 통계·같은 DOM의 전/후 CSS 비교 스크립트는 세션 scratch에 작성했고 계측 JSON은 증거에 보존한다. 새 제품 의존성·프레임워크 없음.
  • 게이트: tests/browser/u07 10/10, U03 29/29, U02 22/22, U01 16/16, CSS 단위 38/38. Phase별 npm run check 및 필수 precheck 기록은 아래에 분리한다. SQL·migration·pgTAP 변경 없음.
  • 버그리포트: BUG-109 (로컬 CSS 순서 교란 재현, Production 신고로 해석하지 않음).

Phase 현황

Phase내용상태
Phase 1import·layer·scope·computed 기준선 및 순서 재현완료, 9e62e93f
Phase 2intrinsic 통합·중복·불필요 important 정리완료, 2205ad9d
Phase 3미사용 scaffold 및 파일 전용 검사 정리완료, d04c6386
Phase 4탐색 순서·좁은 화면·회귀·계약 인계완료, bcb9400b

1. 배경

U01 primitive 계약, U02 모바일 이식, U03 데스크톱 반응형을 실제 release에서 받은 뒤 CSS 소유권을 정리했다. 직접 선행 PR #1317/#1520/#1523과 캠페인 D11 #1547까지 포함한 d058cbb7이 제품 CSS 기준이다. D11의 SQL 계약 보완 #1548을 받은 merge 98d35f4f에서 보류했던 Phase 1·2 check를 통과시켰다.

2. 문제 제기

같은 layer의 뒤쪽 덮어쓰기가 파일 순서에 의존했다

U03의 intrinsic.css가 기존 rule 뒤에서 같은 선택자의 responsive 값을 덮었다. 로컬 Vite style 순서를 뒤집으면 sidebar가 180→236px로 돌아가며 editor/compose/home/PR/volume 5개 회귀가 실패했다. 실제 운영 사용자에게 발생했다는 관측은 없다. 시험은 임의 잘못된 padding도 감지하여 단순 DOM 존재나 timeout을 성공으로 취급하지 않는다.

반복 규칙과 사용 종료 파일의 판단 근거가 달랐다

소스 CSS 30개에 반복 선택자 그룹 64개와 같은 rule의 정확히 같은 선언 2개가 있었다. 중복 property 중 유효 fallback은 제거 대상이 아니다. vite-scaffold.css는 문자열 소비자가 남아 있어도 실제 entry import와 빌드에는 없었고, 전용 정적 테스트만 320px 문자열을 읽고 있었다.

3. 해결 방안

원칙과 접근

D1(2026-09-10): 승인된 #1532 범위를 끝까지 수행한다. 값·디자인·저장/서버 계약을 바꾸지 않고 실제 소유 rule로 통합한다.

판단
원 소유 layer/rule에 통합하고 조건 규칙은 기본 rule 뒤에 둠채택. 순서 의존의 원인을 줄이고 변경 위치를 명확히 함
새 파일 끝 override·important·재시도로 덮음기각. 경쟁 rule과 진입 순서 의존을 남김
CSS Modules/Tailwind·전역 palette 통합·important 전부 삭제기각. 승인 범위를 넘고 필요한 플랫폼/상태 예외를 잃음

4. 적용한 내용

Phase 1 — 기준선과 실패 재현

실제 desktop root/화면 CSS를 기존 U03 fixture에 연결했다. 5개 desktop 화면 style reverse/rotate, 두 플랫폼의 편집 중 lazy CSS 진입·반대 플랫폼 scope·로컬 폰트 검사를 고정했다. 최초 5실패/2통과 → 통합 후 7통과다.

Phase 2 — 소유 rule로 이동

intrinsic.css의 46개 선택자를 desktop.css와 plan-editor/session/pr/volume에 통합했다. 같은 값·조건·layer를 유지했고 충돌 가능성이 없는 반복 규칙만 병합했다. PR board 1180px media를 기본 rule 뒤로 옮겨 border/padding important 3개를 제거했다. narrow 14px/0px/0px, wide 2px/30px/1px 값을 별도로 확인한다.

Phase 3 — 사용 종료 CSS 삭제

vite-scaffold.css와 파일 전용 read/문자열 단언·분류를 삭제했다. 실제 host breakpoint/safe-area 검사와 320px 모바일 브라우저 동작 검사는 유지했다. AppRoot/타입은 R01 경계다. deadByFile은 원래 빈 객체였으므로 baseline 재생성·숫자 감소를 만들지 않았다.

Phase 4 — 회귀와 인계

실제 home/PR/volume 탐색 순서를 바꿔 direct entry와 960/1440px computed style을 비교한다. 320px overlay 취소 뒤 저장 0·원문 12.·포커스·가로 넘침 없음을 확인한다. U03의 실제 200% zoom·긴 텍스트·30번째 입력·dialog/leave/focus/scroll, U02의 복구/편집, U01 primitive를 함께 검증했다. 소유·예외·U04/U06/R01 인계를 갱신했다.

주요 결정과 그 근거

28개 반복 선택자 그룹과 5개 important는 경쟁 rule/inline 상태/화면 예외를 고려해 남겼다. host·group의 기존 unlayered 범위, 모바일/데스크톱 token 값, local font swap, 네 방향 safe-area·bottomChrome 유도식, 동적 클래스 5개 prefix/32개 명시 정의 및 현재 CSS 매칭 63개 클래스과 fallback을 보존했다. 제거 조건은 계약에 기록했다.

작업 중 드러난 것

Phase 1·2의 첫 check는 선행 D11의 reader 변경 뒤 SQL source 계약 6개가 실패하여 완료 보고를 검증 보류로 정정했다. 담당 D11이 #1548로 고쳤고 U07은 SQL 수정 없이 release를 반영해 3,572 통과/0실패/88 skip을 확인했다. U07의 필수 precheck도 생략 없이 통과했다.

계측에서 Vite build와 dev reload 동시 실행, hover가 걸린 포인터, 내부 base CSS를 manifest 밖에 직접 import한 탐색은 각각 timeout/거짓 차이를 만들었다. build와 측정을 분리하고 포인터를 지면 밖으로 옮기며 실제 layer manifest로만 로드한 뒤 재측정했다. 실패·탐색 출력을 성공으로 집계하지 않았다. 최종 standalone build는 명시적 BARBELIC_TARGET=local로 수행했다(최초 target 없는 호출은 guard가 거부).

G05 전체 검사에는 기존 미분류/entry·다른 영역 장부 누락이 있어 전역 통과로 보고하지 않는다. U07의 새 tests 분류와 삭제 CSS 규칙·해당 장부만 정리했다. 다른 담당 범위의 분류 감사를 추가하지 않았다.

5. 적용 결과

항목전 → 후 / 결과
CSS 소스 파일·바이트30 → 28개, 787,484 → 784,170 bytes
rule·declaration5,324 → 5,263 / 21,157 → 21,096
같은 context·selector 반복 그룹64 → 28 (36개 감소, 반복 자체를 전부 결함으로 판정하지 않음)
같은 rule의 정확히 같은 선언2 → 0
important 선언8 → 5
실제 빌드 CSS12 → 12 assets, 518,806 → 517,995 bytes (811 감소)
asset별 gzip 합94,532 → 94,372 bytes (160 감소); 실제 네트워크 요청량/성능 지표와 다름
deadByFile0 → 0, 기준선·동적 예외 unchanged
동일 DOM 전/후 CSSdesktop 5화면×960/1440 + mobile390 두 번, 12회 모두 32개 속성 차이 0
순서 회귀원본 5실패/2통과 → 7/7, 실제 탐색·320px 추가 후 10/10 (15.9초)
기존 브라우저U03 29/29(28.2초), U02 22/22(33초), U01 16/16(8.9초)
Phase checkPhase 1·2 최종/Phase 3: 3,572 통과·0실패·88 조건부 skip; Phase 4도 3,572 통과·0실패·88 조건부 skip
필수 precheck2026-09-10 20:33 KST, bcb9400b / base00a93ad3, static·unused·local build/artifact 통과, unit-1 1682/0/37skip, unit-2 1890/0/51skip, 3분20초. 서버 변경 없음으로 DB 미선택; 브라우저 제외 precheck
Merge Check·releaseMerge Check 34472062355 성공(1분20초), PR #1549의 4a642ad3 원격 release 및 자기 HEAD 포함 확인. full CI 결과와 구분
미실행실제 native/WebKit/Firefox/IME/screenreader·Production 인증 여정·U04 이후 최종 U06·staging/Production 배포

32개 속성 비교는 해당 fixture DOM의 computed style이며 모든 selector·모든 동적 상태의 완전 증명은 아니다. PR·compose 화면을 육안 검토했고 수평 스크롤과 dialog 내부 스크롤 계약은 브라우저 단언으로 확인했다. 기존 88 skip에는 환경 조건과 #1478 제외가 있으며 통과 건수에 합치지 않았다.

6. 이번 개선으로 향상된 것

화면 담당자가 원 소유 파일에서 반응형 규칙을 찾을 수 있다

별도 intrinsic override 1개를 제거하고 같은 layer·조건의 최종값을 원 rule에 모았다. 이후 화면 수정이 뒤쪽 파일의 숨은 덮어쓰기와 충돌할 지점을 줄였다.

후속 목록 변경에 사용할 비교 기준이 남았다

실제 탐색·style 순서·scope·편집 원문·focus·scroll의 회귀 검사와 남긴 예외/제거 조건을 남겼다. 소스 감소와 번들 감소를 분리하여 효과를 과장하지 않는다.

남은 것

U04의 가상 목록 이후 행 높이/scroll·확대/긴 텍스트를 U06에서 재확인한다. native·safe-area·음성 접근성·최종 인증 화면은 U06/R05 경계다. R01에는 미연결 AppRoot/타입을 인계한다. 이 트랙의 release 반영은 Production 배포나 #1532 이슈 종결이 아니다.