HTML-CSS

반응형 웹과 미디어 쿼리(Media Query)

GoJay 2024. 11. 4. 23:33

반응형 페이지란?

뷰포트(Viewport) 사이즈에 따라 정적인 웹 페이지의 요소가 잘 보이지 않거나, 텍스트의 줄 바꿈이 깨지는 경우가 있다. 때론 디바이스에 따라 요소들의 배치, 사이즈, 구성 등을 유연하게 조정해줘야 하는 경우도 있다. 즉, 사용자가 웹 페이지에 접근한 디바이스의 종류나 뷰포트 사이즈(웹 애플리케이션이 구동되고 있는 프로그램의 사이즈) 등 환경에 따라 UI가 유동적으로 바뀌는 게 필요할 수 있는 셈이다.

이러한 필요로 인해 등장한 것이 반응형 페이지(Responsive Page)이다. 반응형 페이지는 사용자가 웹 애플리케이션을 사용하는 환경을 고려해서 HTML과 CSS 요소가 뷰포트 사이즈 변동에 따라 유기적으로 변동된다.

반응형 페이지와 함께 자주 언급되는 개념으로 '적응형 페이지(Adaptive Page)'가 있다. 적응형 페이지도 사용자가 애플리케이션을 사용하는 환경을 고려하는 방식이다. 다만, 적응형 페이지의 다른 점은, 사용자의 환경에 따라 전혀 다른 HTML과 CSS 파일을 적용시킨다는 것이다. 즉, 데스크톱과 모바일에서 각각 적응형 페이지 서비스를 사용한다면 데이터를 처리해 주는 서버는 공유될 수 있겠지만, 사실상 서로 다른 정적 파일이 적용되기 때문에 다른 웹 사이트라고 해도 과언이 아니다(실제로 적응형 페이지로 기기에 따라 기능이나 로직의 차이를 두기도 한다).

반응형 페이지는 이와 달리, 하나의 HTML-CSS 페이지 내에서 사용자의 환경을 고려해 다른 배치와 디자인을 적용하는 식으로 구현된다. 즉, 반응형 페이지의 경우 웹과 모바일이 동일한 HTML-CSS 파일을 공유한다는 것이다. 그리고, 해당 방식의 개발을 하기 위한 다양한 방식이 있다.

HTML-CSS와 반응형

HTML과 CSS는 기본적으로 반응형으로 동작한다. 예를 들어, 아래와 같이 아무 태그로도 감싸지 않고 긴 문장을 표현해보면 문장이 뷰포트 사이즈의 변화에 따라 자동으로 줄 바꿈이 되는 게 확인된다.

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>EXAMPLE</title>
    </head>
    <body>
        Lorem ipsum odor amet, consectetuer adipiscing elit. Mi rutrum interdum tempor morbi vel
        himenaeos taciti. Conubia hendrerit et sed bibendum pretium class. Rhoncus hendrerit ipsum
        sagittis placerat non id. Dignissim fringilla commodo parturient ridiculus ligula a quisque
        senectus. Vestibulum feugiat venenatis ex sagittis conubia. Enim rutrum convallis sit
        habitasse litora eget mattis amet. Risus dignissim dictum maecenas; rutrum fames faucibus.
        Vehicula suspendisse dictum suspendisse ultrices tempus. Condimentum rhoncus sagittis
        blandit semper sociosqu in. Interdum tempor aptent quis enim nec erat. Natoque a maximus
        neque est sollicitudin? Luctus praesent leo mollis convallis conubia diam parturient. Magna
        taciti nostra dictum scelerisque cubilia augue. Senectus in viverra ornare venenatis
        molestie leo. Ut phasellus nam finibus natoque inceptos. Gravida himenaeos natoque mus proin
        senectus morbi amet. Parturient per mi mauris platea ut.
    </body>
</html>

작성한 문장이 뷰포트 사이즈 변경, 화면의 배율 변경에 반응하여 자동으로 줄바꿈을 해주고 있다. 물론, 모든 HTML의 요소가 반응형으로 동작하는 것은 아니지만, 그래도 기본적으로 HTML은 사용자의 이용 환경에 대한 고려를 어느 정도는 알아서 해주고 있는 셈이다.

만약에 CSS까지 함께 사용한다면 좀 더 쉽게 여러 요소를 반응형으로 처리할 수 있다. 예를 들어, div 요소의 크기를 뷰포트 width 사이즈 기준 퍼센티지(%)로 적용하면 뷰포트 사이즈의 변경에 맞게 자동으로 요소의 크기가 변경되는 게 확인된다(div 태그 안에 있는 p 태그는 반응형으로 자동 줄 바꿈이 되기 때문에 박스 영역을 벗어나지 않고 함께 반응형 처리가 잘 이루어진다).

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="./style.css" />
        <title>EXAMPLE</title>
    </head>
    <body>
        <div class="container">
            <p class="text">
                Lorem ipsum odor amet, consectetuer adipiscing elit. Mi rutrum interdum tempor morbi
                vel himenaeos taciti. Conubia hendrerit et sed bibendum pretium class. Rhoncus
                hendrerit ipsum sagittis placerat non id. Dignissim fringilla commodo parturient
                ridiculus ligula a quisque senectus. Vestibulum feugiat venenatis ex sagittis
                conubia. Enim rutrum convallis sit habitasse litora eget mattis amet. Risus
                dignissim dictum maecenas; rutrum fames faucibus. Vehicula suspendisse dictum
                suspendisse ultrices tempus. Condimentum rhoncus sagittis blandit semper sociosqu
                in. Interdum tempor aptent quis enim nec erat. Natoque a maximus neque est
                sollicitudin? Luctus praesent leo mollis convallis conubia diam parturient. Magna
                taciti nostra dictum scelerisque cubilia augue. Senectus in viverra ornare venenatis
                molestie leo. Ut phasellus nam finibus natoque inceptos. Gravida himenaeos natoque
                mus proin senectus morbi amet. Parturient per mi mauris platea ut.
            </p>
        </div>
    </body>
</html>
.container {
    width: 60%;
    background-color: #38bdf8;
    border-radius: 10px;
    padding: 20px 40px;
}

.text {
    font-size: 14px;
    text-align: justify;
}

이외에도 flex, grid 등을 사용해 요소들의 영역을 잡고, 자연스럽게 반응형으로 동작하도록 사용이 가능하다. 즉, 기본적으로 HTML과 CSS는 사용자의 환경에 맞게 반응형으로 요소를 배치하기 위한 최소한의 기능이 제공되는 셈이다.

미디어 쿼리(Media Query)

HTML과 CSS는 반응형 구현을 위한 다양한 기능을 이미 제공하고 있다. 뿐만 아니라, 자바스크립트의 이벤트 객체와 DOM API까지 이용하면 사실상 모든 반응형 처리를 하는 것이 가능하다(예를 들어, 자바스크립트의 전역 window 객체의 사이즈 변화를 resize 이벤트로 감지하고, window.innerWidthwindow.innerHeight를 이용해 뷰포트의 사이즈를 수치로 받아와서, 조건문을 통해 분기처리한 후 원하는 요소의 클래스 명을 추가하거나 삭제해 가면서 CSS를 원하는 방식으로 다르게 적용하는 것이 가능하다).

말로 설명은 해놨지만, 실제로 구현을 해보지 않은건 너무나도 귀찮기 때문이다. 자바스크립트로 뷰포트 사이즈 변화를 감지하려면 window 객체에 이벤트 핸들러를 달아줘야 하고, 이벤트가 발생하면 window 객체에서 지속적으로 변하는 widthheight 값을 관찰하고(디바운스나 스로틀링을 사용하면 이벤트 발생 횟수를 제어할 수 있지만, 아무튼 개발자에게나 컴퓨터에게나 많은 비용이 드는 일이긴 하다), 조건에 맞는 분기문과 요소에 클래스 추가, 그리고 클래스 변화에 따라 다르게 적용될 CSS 작성을 모두 해줘야 한다. 이 모든 걸 해둬야 HTML, CSS, 자바스크립트만 가지고 반응형 구현이 가능한 것이다.

하지만, 이러한 방식은 너무나 귀찮고 번거롭기 때문에, 해당 과정을 도와주는 도구를 사용하는 것이 권장된다. 그리고, 해당 작업에 사용될 수 있는 도구가 바로 미디어 쿼리(Media Query)이다.

미디어 쿼리는 CSS가 제공하는 자체적인 기능이다(CSS 표준에 포함되어있다). 미디어 쿼리의 사용 문법은 아래와 같다.

@media media-type and (media-feature-rule) {
  /* 적용할 CSS */
}

일단 해당 문법을 사용해서 반응형 처리를 해보고, 그 다음 각각에 대해 좀 더 자세히 살펴보겠다. 아래는 미디어 쿼리를 이용해 뷰포트 사이즈가 600px보다 작아지면 div 컨테이너의 색깔을 변경하는 코드다.

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <style>
            .container {
                background-color: #38bdf8;
                width: 500px;
                height: 500px;
            }

            @media screen and (max-width: 600px) {
                .container {
                    background-color: #f85a4b;
                }
            }
        </style>
        <title>EXAMPLE</title>
    </head>
    <body>
        <div class="container"></div>
    </body>
</html>

하나씩 살펴보겠다. 먼저, 미디어 쿼리를 사용하기 위해 @media라는 CSS 조건부 스타일을 문법을 사용해야 한다. 그리고, @media 바로 뒤에는 screen은 웹 애플리케이션이 사용되는 미디어 유형을 의미한다. screen은 데스크톱-모바일 기기의 화면을 의미하며, 인쇄를 위한 미디어 쿼리에선 print를 사용한다(HTML는 '문서'고, CSS는 '문서를 꾸미기 위한 스타일링 언어'이다. 기본적으로 문서를 전제하기 때문에 미디어 유형에 인쇄가 고려된 것 같다).

미디어 유형 위치에 allonly도 사용할 수 있다. all을 쓰면 모든 미디어 유형을 전부 고려하는 미디어 쿼리가 되고, only를 쓰면 하나의 미디어 유형만을 고려하게 된다(only screen처럼 사용한다). 미디어 유형을 정의하지 않으면 기본적으로 all이 적용된다.

미디어 유형 다음, and는 앞과 뒤에 있는 모든 조건이 일치할 때를 의미한다. 그리고 and 뒤에 있는 max-width: 600px는 미디어 쿼리가 적용되는 조건을 의미한다. 작성한 쿼리는 뷰포트의 최대 width600px일 때를 의미하기 때문에, 뷰포트가 600px 이하일 땐 미디어 쿼리 안에 있는 CSS가 적용되고, 600px 초과일 땐 미디어 쿼리 밖의 CSS가 적용된다.

참고로, 미디어 쿼리의 CSS는 미디어 쿼리 밖에 선언된 같은 CSS 속성을 덮어쓰고, 선언되지 않은 CSS 속성을 추가하기만 한다. 미디어 쿼리 밖의 CSS를 완전히 덮어쓰는 게 아니다. 아래 예시를 보면, 미디어 쿼리 밖에서 선언된 border-radius: 15px는 미디어 쿼리 안에서 조건에 해당하는 CSS가 적용될 때에도 동일하게 적용되는 게 확인된다.

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <style>
            .container {
                background-color: #38bdf8;
                border-radius: 15px;
                width: 500px;
                height: 500px;
            }

            @media screen and (max-width: 600px) {
                .container {
                    background-color: #f85a4b;
                }
            }
        </style>
        <title>EXAMPLE</title>
    </head>
    <body>
        <div class="container"></div>
    </body>
</html>

 

결론

모든 반응형 웹을 구현하는 데 있어서 미디어 쿼리가 능사는 아니다. flexgrid를 잘 이용하면 미디어 쿼리의 도움 없이도 적절하게 반응형 처리를 하는 게 가능하다. 물론, 미디어 쿼리는 사용법도 간단하고, 굉장히 직관적으로 적용이 가능하기 때문에, 필요에 따라서 적절히 활용해도 문제는 없을 것 같다(사실, 사이드 이펙트가 있는지 확인해 본 건 아니긴 하다. 그래도 CSS 표준 문법이고, 외부의 도구를 가져와서 사용하는 게 아니기 때문에, 사이드 이펙트가 덜 하지 않을까 생각한다).

포스트에선 미디어 쿼리의 간단한 사용법만 알아봤다. 미디어 쿼리에도 보다 디테일하고 많은 내용들이 있긴 한데, 자세한 미디어 쿼리 사용에 대한 정보는 MDN 문서에서 참조할 수 있다(굳이 다 외울 필요 없이, 필요할 경우 찾아보면서 하면 될 것 같다).