안녕하세요! 지난번 유저의 시력을 위협하던 다크 모드 깜빡임(FOUC)은 무사히 잠재우셨나요? 블로킹 스크립트 한 줄의 위력을 실감하셨길 바랍니다! 자, 오늘은 프론트엔드 개발자들의 영원한 숙제이자 멘탈을 탈곡기로 돌려버리는 지독한 호환성 지옥, '크로스 브라우징(Cross Browsing)'에 대해 이야기해 볼까 합니다.
열심히 코딩을 마치고 최신 크롬 브라우저에서 화면을 확인합니다. Flexbox와 Grid를 팍팍 써서 만든 레이아웃은 1픽셀의 오차도 없이 정말 아름답죠. 뿌듯하게 배포를 마쳤는데, 얼마 뒤 기획자분이나 부장님이 다급하게 메신저를 보냅니다. "개발자님! 제 아이폰으로 들어가니까 카드 목록들이 다닥다닥 붙어서 화면이 완전히 깨져서 나오는데요?"
식은땀을 흘리며 확인해 보면, 내 크롬이나 최신 기기에서는 멀쩡한데 꼭 특정 연차 이상의 구형 아이폰(Safari)이나 오래된 태블릿에서만 화면이 무참히 박살 나 있는 현상. 다들 한 번쯤 겪어보셨죠? (웃음) 오늘은 대체 왜 이런 일이 벌어지는지, 그리고 어떻게 이 크로스 브라우징의 악몽에서 벗어날 수 있는지 실전 팁을 모두 방출하겠습니다.

1. 부장님의 아이폰에서는 화면이 다 깨져서 나옵니다
예전에는 인터넷 익스플로러(IE)가 웹 개발자들의 공공의 적이었죠. 하지만 IE가 역사 속으로 사라진 지금, 그 자리를 꿰찬 새로운 빌런(?)이 있습니다. 바로 사파리(Safari) 구버전입니다.
애플 기기들은 OS 업데이트를 하지 않으면 사파리 브라우저 버전도 그대로 멈춰버립니다. 최신 CSS 문법을 아무리 예쁘게 짜놔도, 구형 사파리를 쓰는 유저의 브라우저는 그 문법을 해석하지 못하고 "이게 무슨 소리야?" 하면서 레이아웃을 다 무너뜨려 버리는 것이죠.
2. 단골 범인은 바로 Flexbox의 gap 속성!
실무에서 가장 빈번하게 화면을 깨뜨리는 주범은 다름 아닌 Flexbox의 gap 속성입니다. 여러 요소 사이의 간격을 띄울 때 gap: 16px; 한 줄이면 끝나니까 너무 편하잖아요?
그런데 이 Flexbox의 gap 속성은 사파리 14.1 버전(2021년 4월 출시)부터 지원하기 시작했습니다. 즉, iOS 14.1 미만을 사용하는 유저들의 화면에서는 gap이 아예 무시되어 버립니다. 마진(margin) 없이 카드들이 찰싹 달라붙어버리니 레이아웃이 엉망진창이 될 수밖에 없죠. Grid에서는 예전부터 gap이 지원되었지만, Flexbox에서는 비교적 최근에 도입된 문법이라 생기는 비극입니다.

3. 실전 해결책 1: @supports와 마진(margin)으로 폴백(Fallback) 만들기
이럴 때 가장 정석적인 해결 방법은, 구형 브라우저를 위한 '플랜 B(Fallback)' 코드를 먼저 적어두고, 최신 브라우저를 위한 코드를 덮어씌우는 것입니다.
예전 방식인 음수 마진(Negative Margin)과 자식 요소의 마진을 이용해 간격을 만들어주고, CSS의 기능 지원 여부를 묻는 @supports 문법을 활용합니다.
/* 기본값: gap을 지원하지 않는 구버전 브라우저를 위한 마진(margin) 플랜 B */
.flex-container {
display: flex;
flex-wrap: wrap;
margin: -8px;
}
.flex-item {
margin: 8px;
}
/* 최신 브라우저라면? 위의 마진 설정을 끄고 깔끔하게 gap을 써라! */
@supports (gap: 16px) {
.flex-container {
margin: 0;
gap: 16px;
}
.flex-item {
margin: 0;
}
}
이렇게 방어 코드를 짜두면, 부장님의 구형 아이폰에서도 마진을 통해 간격이 예쁘게 유지되고, 최신 기기에서는 성능 좋은 gap 속성이 부드럽게 적용됩니다.
4. 실전 해결책 2: Autoprefixer와 browserslist로 벤더 프리픽스 챙기기
gap 외에도 호환성을 타는 CSS 속성들은 무수히 많습니다. 브라우저마다 -webkit-, -moz- 같은 접두사(Vendor Prefix)를 붙여줘야 하는 경우도 있죠. 이걸 사람이 일일이 외워서 적는 건 불가능합니다.
그래서 우리는 PostCSS의 Autoprefixer라는 훌륭한 도구를 사용해야 합니다. 프로젝트 루트에 .browserslistrc 파일이나 package.json에 browserslist 설정을 적어두세요. 예를 들어 > 1%, last 2 versions, not dead 라고 설정해 두면, 빌드할 때 Autoprefixer가 알아서 전 세계 점유율 1% 이상의 브라우저들을 분석한 뒤, 구버전에 필요한 호환성 코드를 자동으로 CSS에 끼워 넣어 줍니다.
마무리하며
오늘은 프론트엔드 개발자들을 허탈하게 만드는 "내 로컬 크롬에서는 예쁜데!"의 주범, 크로스 브라우징 문제와 Flexbox gap 속성 대응법에 대해 알아보았습니다. 새로운 CSS 문법이 나오면 신나게 가져다 쓰는 것도 좋지만, Can I Use 사이트에서 브라우저 지원 범위를 한 번씩 검색해 보는 습관을 들이는 것이 중요합니다. 오늘 알아본 @supports 폴백 코드와 Autoprefixer 설정을 통해, 어떤 구형 브라우저로 접속해도 깨지지 않는 튼튼하고 단단한 UI를 완성해 보시길 바랍니다!
[다음 포스팅 예고] 화면 깨짐 지옥에서 무사히 빠져나오셨나요? 자, 대망의 11번째 시리즈에서는 백엔드와 프론트엔드 모두를 멘붕에 빠뜨리는 배포 환경의 미스터리를 파헤쳐 보겠습니다. "로컬에서는 잘 되는데 배포 환경에서는 안 되는 환경변수(.env) 문제 추적기" 편으로 돌아오겠습니다. 내 컴퓨터에선 API 호출이 잘만 되는데, Vercel이나 AWS에 올리기만 하면 undefined를 뿜어내는 기이한 환경변수의 비밀을 속 시원히 밝혀드릴 테니 다음 글도 절대 놓치지 마세요! 오늘도 버그 없는 평온한 하루 보내시길 응원합니다!
[실무에서 복붙해 쓰는 에러 해결 및 트러블슈팅 가이드 #11] 내 로컬에선 잘 되는데? 배포만 하
안녕하세요! 지난번 사파리 브라우저의 화면 깨짐 지옥에서는 무사히 빠져나오셨나요? 호환성 대응 코드로 단단해진 UI를 완성하셨길 바랍니다! 자, 오늘은 개발자라면 누구나 한 번쯤 외쳐봤을
code-bricks.tistory.com