안녕하세요! 프론트엔드 개발자 취업을 향해 열심히 달려가고 계시군요. MDN 공식 문서를 통해 원리를 꼼꼼하게 다지시는 모습이 정말 훌륭합니다!
오늘 가져오신 문서는 단순히 CSS를 넘어서, 자바스크립트를 이용해 화면(뷰포트)의 상태를 감지하고 조작하는 핵심적인 기술을 다루고 있어요. 원본 문서의 내용을 하나도 빠짐없이, 이해하기 쉬운 구어체로 번역해 드릴게요. 중간중간 실무에서 어떻게 쓰이는지, 제 경험을 녹여낸 팁과 부연 설명도 듬뿍 담았으니 천천히 읽어보세요!
DOM(문서 객체 모델)은 MediaQueryList 인터페이스와 여기서 제공하는 메서드 및 프로퍼티들을 통해 프로그래밍 방식으로 미디어 쿼리(media query)의 결과를 테스트할 수 있는 기능을 제공합니다.
일단 MediaQueryList 객체를 생성하고 나면, 해당 쿼리의 결과를 확인하거나 결과가 바뀔 때마다 알림(이벤트)을 받을 수 있답니다.
💡 강사의 부연 설명 & 실무 팁 1
CSS 파일 안에서@media (max-width: 768px)를 사용하는 것과, 이렇게 자바스크립트 DOM API를 사용하는 것은 어떤 차이가 있을까요? CSS는 단순히 시각적인 '스타일'만 변경할 수 있습니다. 반면 자바스크립트의matchMedia를 사용하면 화면 크기에 따라 완전히 다른 기능을 실행하거나, React 등에서 렌더링할 컴포넌트 자체를 교체할 수 있습니다.
예를 들어 모바일에서는 '햄버거 메뉴' 컴포넌트를, 데스크톱에서는 '전체 네비게이션' 컴포넌트를 렌더링하고 싶을 때 이 기능이 필수적으로 쓰입니다.
미디어 쿼리의 결과를 평가(확인)하려면, 먼저 해당 쿼리를 나타내는 MediaQueryList 객체를 만들어야 해요. 이 객체를 만들려면 window.matchMedia 메서드를 사용합니다.
예를 들어, 현재 기기가 가로 모드(landscape)인지 세로 모드(portrait)인지를 결정하는 방향(orientation) 쿼리 리스트를 설정하려면 다음과 같이 작성합니다.
const mediaQueryList = window.matchMedia("(orientation: portrait)");
미디어 쿼리 리스트를 성공적으로 생성했다면, 객체의 matches 프로퍼티 값을 통해 쿼리 결과를 곧바로 확인할 수 있어요.
if (mediaQueryList.matches) {
/* 뷰포트가 현재 세로 모드(portrait)입니다 */
} else {
/* 뷰포트가 현재 세로 모드가 아닙니다. 따라서 가로 모드(landscape)입니다 */
}
💡 강사의 실무 팁 2
이 코드는 실행되는 그 순간의 상태만 검사합니다. 만약 사용자가 핸드폰을 돌려서 가로/세로가 바뀌거나, 브라우저 창 크기를 드래그해서 줄인다면 어떻게 될까요? 변경된 사실을 알기 위해서는 지속적인 모니터링이 필요한데, 그 방법이 바로 아래에 나옵니다!
미디어 쿼리의 평가 결과가 변하는 것을 지속적으로 파악해야 한다면, 쿼리 결과를 계속해서 폴링(polling, 주기적으로 값을 확인하는 방식)하는 것보다 리스너(listener)를 등록하는 것이 훨씬 효율적입니다.
이렇게 하려면 MediaQueryList 객체에 addEventListener() 메서드를 호출하면서, 미디어 쿼리 상태가 바뀔 때(예: 평가 결과가 true에서 false로 바뀔 때) 실행될 콜백 함수를 넘겨주면 됩니다.
// 쿼리 리스트를 생성합니다.
const mediaQueryList = window.matchMedia("(orientation: portrait)");
// 이벤트 리스너로 사용할 콜백 함수를 정의합니다.
function handleOrientationChange(mql) {
// …
}
// 방향 변경 핸들러를 처음에 한 번 수동으로 실행해줍니다.
handleOrientationChange(mediaQueryList);
// 쿼리 리스트에 콜백 함수를 리스너로 추가합니다.
mediaQueryList.addEventListener("change", handleOrientationChange);
위 코드는 기기의 방향을 테스트하는 미디어 쿼리 리스트를 만들고, 거기에 이벤트 리스너를 추가하는 내용입니다. 리스너를 정의한 후에, 우리가 직접 리스너 함수를 한 번 호출하고 있다는 점에 주목해 주세요.
이렇게 하면 리스너가 기기의 현재 방향을 기반으로 즉시 조정을 수행할 수 있습니다. 만약 이렇게 하지 않으면, 현재 기기가 가로 모드임에도 불구하고 우리 코드는 앱이 켜질 때 세로 모드일 것이라고 잘못 가정할 위험이 있거든요.
handleOrientationChange() 함수는 쿼리의 결과를 확인하고 화면 방향이 바뀌었을 때 우리가 해야 할 일들을 처리하게 됩니다.
function handleOrientationChange(evt) {
if (evt.matches) {
/* 뷰포트가 현재 세로 모드(portrait)입니다 */
} else {
/* 뷰포트가 현재 가로 모드(landscape)입니다 */
}
}
위 코드에서 우리는 매개변수를 evt로 정의했어요. 이 evt는 MediaQueryListEvent 타입의 이벤트 객체로, media와 matches 프로퍼티를 포함하고 있습니다. 그래서 MediaQueryList 객체에 직접 접근하거나, 이 이벤트 객체를 통해서 쿼리의 특징들을 조회할 수 있죠.
💡 강사의 실무 팁 3
React 환경에서는 이 로직을 커스텀 훅(useMediaQuery등)으로 만들어서 캡슐화해 사용하는 패턴이 국룰입니다!
컴포넌트 안에서useEffect를 활용하여matchMedia리스너를 등록하고, 결과값을 Zustand 같은 상태 관리 도구와 연동해 전역 상태로 뿌려주면 매우 깔끔한 컴포넌트 주도 개발(CDD)을 할 수 있습니다. Next.js를 쓰실 때는 서버 사이드 렌더링(SSR) 시점에는window객체가 없다는 점을 고려해서 방어 코드를 짜는 것도 잊지 마시고요!
미디어 쿼리의 값이 변경되는 것에 대한 알림을 그만 받고 싶다면, MediaQueryList 객체에서 removeEventListener() 메서드를 호출하면 됩니다. 이때 앞서 정의했던 콜백 함수의 이름을 함께 전달해야 해요.
mediaQueryList.removeEventListener("change", handleOrientationChange);
💡 강사의 부연 설명 4
화면을 닫거나 다른 페이지로 넘어갈 때(컴포넌트가 언마운트될 때) 메모리 누수(Memory Leak)를 막기 위해removeEventListener를 호출해 주는 것은 프론트엔드 개발자의 필수 덕목입니다.
| Specification (명세) |
|---|
| CSSOM View Module # the-mediaquerylist-interface |
(원본 문서의 복잡한 표를 보기 쉽게 마크다운 형식으로 정리했습니다. MediaQueryList API는 주요 브라우저에서 모두 완벽히 지원됩니다.)
| 기능 (Feature) | Chrome | Edge | Firefox | Opera | Safari | 모바일 환경 지원 여부 |
|---|---|---|---|---|---|---|
MediaQueryList | ✅ 9+ | ✅ 12+ | ✅ 6+ | ✅ 12.1+ | ✅ 5.1+ | 완벽 지원 (Android, iOS 모두 포함) |
EventTarget 상속 | ✅ 39+ | ✅ 16+ | ✅ 55+ | ✅ 26+ | ✅ 14+ | 완벽 지원 |
addListener() ⚠️ | ✅ 9+ | ✅ 12+ | ✅ 6+ | ✅ 12.1+ | ✅ 5.1+ | 완벽 지원 (단, Deprecated) |
change 이벤트 | ✅ 39+ | ✅ 79+ | ✅ 55+ | ✅ 26+ | ✅ 14+ | 완벽 지원 |
matches | ✅ 9+ | ✅ 12+ | ✅ 6+ | ✅ 12.1+ | ✅ 5.1+ | 완벽 지원 |
media | ✅ 9+ | ✅ 12+ | ✅ 6+ | ✅ 12.1+ | ✅ 5.1+ | 완벽 지원 |
removeListener() ⚠️ | ✅ 9+ | ✅ 12+ | ✅ 6+ | ✅ 12.1+ | ✅ 5.1+ | 완벽 지원 (단, Deprecated) |
⚠️ 주의 (Deprecated):
addListener()와removeListener()는 과거에 쓰이던 방식으로, 새로운 웹사이트를 만들 때는 사용을 권장하지 않습니다. 대신 표준 이벤트 기반 방식인addEventListener('change', ...)를 사용하세요!
window.matchMedia()MediaQueryListMediaQueryListEventMDN 향상에 도움 주기 (Help improve MDN)
혹시 번역된 내용 중에서 더 깊게 알고 싶거나, 이 개념을 활용해서 현재 개발 중인 포트폴리오에 직접 적용해보는 코드가 궁금하시다면 편하게 말씀해 주세요! 제가 바로 도와드릴게요.