지금까지 만든 페이지를 반응형으로 한 번 수정해보도록 하겠습니다. 페이지의 화면 크기를 한 번 줄이면 아래와 같이 페이지가 난장판으로 변하게 됩니다.
하지만 반응형 웹 페이지는 크기가 줄어들면 이에 맞게 레이아웃이 변하는 것을 보여주고 있습니다. 이처럼 웹 페이지를 반응형 적용을 추가하여 웹 페이지를 수정해 보도록 하겠습니다.
반응형 웹 사이트를 만들기 앞서 먼저 meta 태그에 설정을 주어야 합니다. meta 태그는 웹 사이트의 설정을 도와주는 역할을 하고 있다고 이해하시면 됩니다. 그래서 meta 태그에 name="viewport" 를 명시해 주어야 반응형 웹 사이트를 만들 수 있습니다. viewport 를 명시하지 않을 경우 형태를 유지하면서 줄어들기 때문에 반응형 웹 사이트의 제작이 불가능합니다.
또한 content 의 모든 크기는 디바이스(PC)와 동일하게 가겠다고 설정하고 최소값과 최대값도 똑같이 크기를 1로 맞춰줍니다.
파일명 :
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <title>Title</title> <link rel="stylesheet" href="css/reset.css"> <link rel="stylesheet" href="css/common.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> ...
viewport 를 명시해 주었다면 반응형 웹 사이트를 만들기 위해선 media 쿼리를 사용하여야 합니다. 중괄호 안에는 최댓값과 최솟값을 입력해주시면 됩니다. 1000px 이하가 되었을때 side_box 가 없어지도록 만들어 보겠습니다.
먼저, 좌우값을 지정해 주었던 것들을 가지고 옵니다. 1000px 이하로 내려갔을 때 좌우값이 바껴야 하는데 픽셀을 주게 되면 더 줄어들 때 마다 픽셀을 고쳐야 하기 때문에 백분율로 계산해서 주도록 하겠습니다. contents는 javascript를 이용하여 설정하는 것이 편합니다.
파일명 :
css/style.css
... @media screen and (max-width:1000px){ #header .inner{ width: 975px; } #main_container .inner{ width: 935px; } .contents{ width: 614px; /* height: 500px; */ border: 1px solid rgba(0,0,0,0.09); border-radius: 3px; /* 테두리를 둥글게 만듬 */ margin-bottom: 60px; /* 다른 contents들이 밀려야 되기 때문에 사이에 여백을 준다 */ background: white; } }
파일명 :
css/style.css
... @media screen and (max-width:1000px){ #header .inner{ width: 97.5%; } #main_container .inner{ width: 93.5%; } }
1000px 이하로 내려갈 경우에 side_box 는 없어지는 기능을 작성해 보겠습니다.
파일명 :
css/style.css
... @media screen and (max-width:1000px){ #header .inner{ width: 97.5%; } #main_container .inner{ width: 93.5%; } .side_box{ /* 사이드 박스 숨기기 */ display: none; } }
크기가 줄어들었을 때 사이드 박스가 사라지는 것을 볼 수 있습니다. 이때, 상대적으로 왼쪽에 쏠린 것을 볼 수 있습니다. 그렇기 때문에 가운데 정렬을 해주도록 하겠습니다.
파일명 :
css/style.css
... @media screen and (max-width:1000px){ #header .inner{ width: 97.5%; } #main_container .inner{ width: 93.5%; } .contents_box{ display: flex; flex-direction: column; /* 세로 배치 받도록 한다 */ align-items: center; /* 왼쪽으로 치우쳐 지는 걸 방지 */ } .side_box{ /* 사이드 박스 숨기기 */ display: none; } }
이번에는 650px 보다 작아질 경우에는 검색 창 부분도 보이지 않게 하도록 해보겠습니다.
파일명 :
css/style.css
... @media screen and (max-width:1000px){ ... } } @media screen and (max-width:650px){ #header .search_box{ display: none; } }
창이 작아졌을 때 나타나는 히든 메뉴를 만들어 보겠습니다.
위치상으로는 header와 main_container 사이에 있기 때문에 해당 부분에 추가해주도록 하겠습니다. 그리고 가로로 스크롤이 가능한 scroll_inner 를 설정하겠습니다. 여기서 조금 살펴봐야 할 부분은 flex-direction: column; 로 인해서 justify-content: space-between;를 적용해도 가로 정렬이 아닌 세로 정렬이 적용되게 된다는 점만 짚고 넘어가시면 됩니다.
파일명 :
index.html
... <header id="header"> ... </header> <div class="hidden_menu"> <div class="scroll_inner"> <div class="user"> <div class="thumb_img"><img src="imgs/thumb.jpeg" alt="프로필사진"></div> <div class="id">kindtigerrr</div> </div> </div> </div> <section id="main_container"> ... </section> ...
파일명 :
css/style.css
... .hidden_menu{ display: none; width: 600px; /* background: red; */ position: absolute; left: 50%; transform: translateX(-50%); /* x축 가운데 정렬 */ top: 100px; overflow: hidden; /* 자식들이 넘치지 않도록 한다 */ border: 1px solid rgba(0,0,0,0.09); border-radius: 3px; } .hidden_menu .scroll_inner{ height: 100px; /* 높이값을 자식에게 준다 */ width: auto; overflow-x: auto; /* 항목이 많아질 경우 알아서 스크롤이 생성 */ overflow-y: hidden; display: flex; /* 가로배치 */ align-items: center; padding: 0 10px; } .hidden_menu .scroll_inner .user{ width: 80px; height: 80px; display: flex; flex-direction: column; /* 가로 중앙 정렬을 세로 중앙 정렬로 변경 */ align-items: center; margin-right: 15px; justify-content: space-between; /* 이미지는 위로 아이디는 아래로 설정 */ } .hidden_menu .scroll_inner .user .id{ font-size: 12px; color: #262626; } .hidden_menu .thumb_img{ width: 56px; height: 56px; border-radius: 50%; overflow: hidden; } .hidden_menu .thumb_img img{ width: 100%; height: 100%; } @media screen and (max-width:1000px){ #header .inner{ width: 97.5%; } #main_container{ padding-top: 220px; } #main_container .inner{ width: 93.5%; } ... .hidden_menu{ display: block; } } @media screen and (max-width:650px){ #header .search_box{ display: none; } .hidden_menu{ width: 95%; } }
완성된 코드는 아래와 같습니다.
파일명 :
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <title>Title</title> <link rel="stylesheet" href="css/reset.css"> <link rel="stylesheet" href="css/style.css"> <script src="js/main.js"></script> </head> <body> <section id="container"> <header id="header"> <section class="inner"> <h1 class="logo"> <a herf="index.html"> <div class="sprite_insta_icon"></div> <div class="sprite_write_logo"></div> </a> </h1> <div class="search_box"> <input type="text" placeholder="검색" id="search-field"> <div class="fake_field"> <span class="sprite_small_search_icon"></span> <span>검색</span> </div> </div> <div class="right_icons"> <div class="sprite_camera_icon"></div> <div class="sprite_compass_icon"></div> <div class="sprite_heart_icon_outline"></div> <div class="sprite_user_icon_outline"></div> </div> </section> </header> <!--**표시까지 반복--> <div class="hidden_menu"> <div class="scroll_inner"> <div class="user"> <div class="thumb_img"><img src="imgs/thumb.jpeg" alt="프로필사진"></div> <div class="id">kindtigerrr</div> </div> </div> </div> <!--**--> <section id="main_container"> <div class="inner"> <div class="contents_box"> <article class="contents"> <header class="top"> <div class="user_container"> <div class="profile_img"> <img src="imgs/thumb.jpeg" alt="프로필이미지"> </div> <div class="user_name"> <div class="nick_name m_text">KindTiger</div> <div class="country s_text">Seoul, South Korea</div> </div> </div> <div class="sprite_more_icon" data-name="more"></div> </header> <div class="img_section"> <div class="trans_inner"> <div> <img src="imgs/img_section/img01.jpg" alt="visual01"> </div> </div> </div> <div class="bottom_icons"> <div class="left_icons"> <div class="heart_btn"> <div class="sprite_heart_icon_outline" name="39" data-name="heartbeat"></div> </div> <div class="sprite_bubble_icon"></div> <div class="sprite_share_icon" data-name="share"></div> </div> <div class="right_icon"> <div class="sprite_bookmark_outline" data-name="bookmark"></div> </div> </div> <div class="likes m_text"> 좋아요 <span id="count">2,346</span> 개 </div> <div class="comment_container"> <div class="comment"> <div class="nick_name m_text">dongdong2</div> <div>강아지가 너무 귀여워요~!</div> </div> <div class="small_heart"> <div class="sprite_small_heart_icon_outline"></div> </div> </div> <div class="timer">1시간 전</div> <div class="comment_field"> <input type="text" placeholder="댓글달기..."> <div class="upload_btn m_text">게시</div> </div> </article> </div> <div class="side_box"> <div class="user_profile"> <div class="profile_thumb"> <img src="imgs/thumb.jpeg" alt="프로필사진"> </div> <div class="detail"> <div class="id m_text">KindTiger</div> <div class="ko_name">심선범</div> </div> </div> <article class="story"> <header class="story_header"> <div>스토리</div> <div class="more">모두 보기</div> </header> <div class="scroll_inner"> <div class="thumb_user"> <!--**표시까지 반복--> <div class="profile_thumb"> <img src="imgs/thumb02.jpg" alt="프로필사진"> </div> <div class="detail"> <div class="id">kind_tigerrrr</div> <div class="time">1시간 전</div> </div> <!--**--> </div> </div> </article> <article class="recommend"> <header class="reco_header"> <div>회원님을 위한 추천</div> <div class="more">모두 보기</div> </header> </article> </div> </div> </section> </section> </body> </html>
파일명 :
css/style.css
.sprite_insta_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -53px -235px; width: 22px; height: 22px; } .sprite_write_logo{ display: inline-block; background: url('../imgs/background01.png') no-repeat -94px -72px; width: 103px; height: 29px; } .sprite_compass_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -130px -286px; width: 23px; height: 23px; } .sprite_user_icon_outline{ display: inline-block; background: url('../imgs/background01.png') no-repeat -272px -182px; width: 22px; height: 24px; } .sprite_heart_icon_outline{ display: inline-block; background: url('../imgs/background01.png') no-repeat -52px -261px; width: 24px; height: 22px; } .sprite_small_search_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -337px -246px; width: 10px; height: 10px; } .sprite_more_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -301px -218px; width: 15px; height: 3px; } .sprite_bubble_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -239px -202px; width: 24px; height: 24px; } .sprite_share_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -324px -52px; width: 21px; height: 24px; } .sprite_bookmark_outline{ display: inline-block; background: url('../imgs/background01.png') no-repeat -237px -286px; width: 19px; height: 24px; } .sprite_bookmark_outline.on{ background: url('../imgs/background01.png') no-repeat -159px -286px; width: 19px; height: 24px; } .sprite_small_heart_icon_outline{ display: inline-block; background: url('../imgs/background01.png') no-repeat -323px -274px; width: 12px; height: 11px; } .sprite_camera_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -271px -104px; width: 24px; height: 22px; } .sprite_insta_big_logo{ display: inline-block; background: url('../imgs/background02.png') no-repeat -98px -150px; width: 175px; height: 51px; } .sprite_plus_icon{ display: inline-block; background: url('../imgs/background01.png') no-repeat -187px -202px; width: 23px; height: 23px; } body{ background: #fafafa; } #header{ width: 100%; /* 공중에 뜨기 위함 */ position: absolute; /* 가장 위에 올라가 있어야 하기 위함 */ z-index: 999; /* absolute의 경우 최소 x축에서 1개 y축에서 1개의 값을 주어야 함 */ left: 0; top: 0; background: white; border-bottom: 1px solid rgba(0,0,0,0.1); } #header .inner{ /* inner 안에 컨텐츠를 넣으면 안에 값이 들어옴 */ width: 975px; height: 77px; margin: 0 auto; /* 가운데 정렬 */ display: flex; /* 가로 배치 */ justify-content: space-between; /* x축 정렬_공간을 자동으로 분배함 */ align-items: center; /* y축 정렬 */ } #header .inner .logo > a{ color: transparent; /* 배경색을 투명하게 만듬 */ } #header .inner .logo div{ vertical-align: middle; } #header .inner .logo .sprite_insta_icon{ position: relative; /* after에게 위치 기준을 전달해주기 위함 */ margin-right: 30px; } #header .inner .logo .sprite_insta_icon:after{ content: ''; /* 공백을 받아옴 */ width: 1px; height: 28px; background: #000; position: absolute; /* 부모를 기준으로 위치를 잡음 */ right: -15px; top: -4px; } #header .search_box{ position: relative; /* 기준점을 잡고 가로 배치 */ } #search-field{ width: 185px; height: 28px; background: #fafafa; border: 1px solid #dbdbdb; border-radius: 3px; padding: 3px 30px; /* 위아래 양쪽 */ color: #999; font-weight: 400; text-align: left; /* 글자 입력 시 왼쪽부터 보이도록 하기 위함 */ font-size: 14px; outline: none; /* 포커스 했을 때 나타나는 파란선 */ } #search-field::placeholder{ /* 콜론2개(::) - 속성선택자 */ font-size: 0; /* 포커스가 되지 않을 때 검색 글자가 보이지 않도록 하기 위함 */ } #search-field:focus::placeholder{ font-size: 14px; /* 포커스 되었을 때 검색 글자가 보이도록 한다 */ } #header .search_box .fake_field{ position: absolute; /* 검색 창 위에 글자를 보이기 위함 */ /* 가운데 배치하는 공식 */ left: 50%; top: 50%; transform: translate(-50%, -50%); pointer-events: none; /* 검색을 눌렀을 때에는 포인터 인식이 안 됨 */ } /* 물결(~) - 근처에 있는 fake_field */ #search-field:focus~.fake_field > span:nth-child(1){ transform: translateX(-105px); /* 돋보기를 왼쪽으로 이동 */ } #search-field:focus~.fake_field > span:nth-child(2){ display: none; /* 포커스 되었을 때 글자 숨기기 */ } #header .right_icons{ width: 132px; /* 부모값 좌우값 고정 */ display: flex; justify-content: space-between; /* x축 정렬_공간을 자동으로 분배함 */ } #header .inner .logo div:nth-child(2){ transform: translateY(2px); } #header .inner .logo .sprite_insta_icon{ position: relative; /* after에게 위치 기준을 전달해주기 위함 */ margin-right: 30px; } #main_container{ padding-top: 130px; display: flex; /* 컨텐츠가 가운데에 위치할 수 있도록 함 */ justify-content: center; /* x축 가운데 정렬 */ } #main_container .inner{ width: 935px; /* height: 500px; */ /* background: red; */ position: relative; /* 기준점을 inner로 변경하기 위함 */ } .contents_box{ } .contents{ width: 614px; /* height: 500px; */ border: 1px solid rgba(0,0,0,0.09); border-radius: 3px; /* 테두리를 둥글게 만듬 */ margin-bottom: 60px; /* 다른 contents들이 밀려야 되기 때문에 사이에 여백을 준다 */ background: white; } .contents .top{ display: flex; /* 가로 배치 */ justify-content: space-between; /* x축 정렬_공간을 자동으로 분배 */ align-items: center; padding: 10px 20px; /* 위아래 양쪽 */ } .contents .top .profile_img{ width: 32px; height: 32px; border-radius: 50%; /* 테두리를 둥글게 설정 50% -> 원의 형태 */ overflow: hidden; /* 자식이 크기가 넘치지 않도록 한다 */ margin-right: 10px; } .contents .top .profile_img img{ width: 100%; /* 100%가 없을 경우 이미지가 들어가지 않음 */ } .contents .top .user_container{ display: flex; /* 가로 배치 */ } .m_text{ font-size: 14px; font-weight: bold; } .s_text{ font-size: 12px; } .contents .img_section{ overflow: hidden; /* 자식이 부모의 크기를 넘지 않도록 한다 */ } .contents .img_section img{ width: 100%; /* 부모의 크기 100%를 받는다 */ } .contents .bottom_icons{ display: flex; /* 가로 배치 */ justify-content: space-between; /* x축 정렬_공간을 자동으로 분배함 */ align-items: center; /* y축 가운데 정렬 */ padding: 10px 20px; } .contents .bottom_icons .left_icons{ display: flex; /* 가로 배치 */ } .contents .bottom_icons .left_icons > div{ margin-right: 10px; } .contents .likes{ padding: 5px 20px; color: #262626; } .contents .comment_container{ display: flex; /* 가로 배치 */ justify-content: space-between; align-items: center; padding: 5px 20px; } .contents .comment_container .comment{ display: flex; /* 가로 배치 */ font-size: 14px; } .contents .comment_container .comment .nick_name{ margin-right: 10px; /* 아이디와 댓글 간의 거리 설정 */ } .contents .timer{ font-size: 10px; letter-spacing: 0.2px; /* 자간 조정 */ color: #999; border-bottom: 1px solid rgba(0,0,0,0.09); /* 아래쪽 실선 추가 */ padding: 10px 20px; } .contents .comment_field{ min-height: 56px; padding: 0 20px; position: relative; /* 자식들이 absolute로 자리를 잡기 위함 */ } .contents .comment_field input{ width: 100%; height: 56px; border: none; outline: none; background: transparent; /* 투명하게 설정 */ } .contents .comment_field input:focus ~ .upload_btn{ pointer-events: initial; /* 포인터 이벤트 초기화 */ opacity: 1; } .contents .comment_field .upload_btn{ color: #3897f0; position: absolute; right: 20px; top: 50%; transform: translateY(-50%); /* y축으로 중앙 정렬 */ cursor: pointer; pointer-events: none; /* 처음에는 클릭이 되지 않도록 한다 */ opacity: 0.6; } .contents .bottom_icons .right_icon > div{ cursor: pointer; /* 누를 수 있도록 하기 위함 */ } .side_box{ width: 293px; /* height: 300px; */ /* background: rgba(255,0,0,0.16); */ position: absolute; /* 부모를 갖는 기준점을 잡지 않으면 꼭대기까지 올라감 */ right: 0; top: 0; } .side_box .profile_thumb{ width: 50px; height: 50px; border-radius: 50%; overflow: hidden; /* 이미지가 넘치지 않도록 한다 */ margin-right: 10px; } .side_box .profile_thumb img{ width: 100%; height: 100%; } .side_box .user_profile{ display: flex; /* 가로 배치 */ align-items: center; font-size: 14px; color: #262626; } .side_box .detail .id{ margin-bottom: 5px; } .side_box .detail .ko_name{ font-size: 12px; color: #999; } .side_box > article{ border: 1px solid rgba(0,0,0,0.09); border-radius: 3px; margin-bottom: 20px; width: 291px; font-size: 14px; color: #262626; font-weight: bold; background: white; } .side_box > article > header{ display: flex; /* 가로 배치 */ align-items: center; justify-content: space-between; padding: 15px 20px; color: #999; } .side_box > article > header .more{ font-size: 12px; color: #262626; cursor: pointer; } .thumb_user{ display: flex; align-items: center; padding: 10px 20px; } .thumb_user .profile_thumb{ width: 34px; /* 크기가 좀 더 작게 만듬 */ height: 34px; } .thumb_user .time{ font-size: 10px; letter-spacing: 0.2px; color: #999; } .side_box .scroll_inner{ height: 182px; overflow-x: hidden; /* x축_자식이 부모 넘지 못하게 한다 */ overflow-y: auto; /* 자동으로 스크롤을 보여주거나 숨김 */ /* overflow: hidden auto; x축, y축 한번에 설정 */ } .hidden_menu{ display: none; width: 600px; /* background: red; */ position: absolute; left: 50%; transform: translateX(-50%); /* x축 가운데 정렬 */ top: 100px; overflow: hidden; /* 자식들이 넘치지 않도록 한다 */ border: 1px solid rgba(0,0,0,0.09); border-radius: 3px; } .hidden_menu .scroll_inner{ height: 100px; /* 높이값을 자식에게 준다 */ width: auto; overflow-x: auto; /* 항목이 많아질 경우 알아서 스크롤이 생성 */ overflow-y: hidden; display: flex; /* 가로배치 */ align-items: center; padding: 0 10px; } .hidden_menu .scroll_inner .user{ width: 80px; height: 80px; display: flex; flex-direction: column; /* 가로 중앙 정렬을 세로 중앙 정렬로 변경 */ align-items: center; margin-right: 15px; justify-content: space-between; /* 이미지는 위로 아이디는 아래로 설정 */ } .hidden_menu .scroll_inner .user .id{ font-size: 12px; color: #262626; } .hidden_menu .thumb_img{ width: 56px; height: 56px; border-radius: 50%; overflow: hidden; } .hidden_menu .thumb_img img{ width: 100%; height: 100%; } @media screen and (max-width:1000px){ #header .inner{ width: 97.5%; } #main_container{ padding-top: 220px; } #main_container .inner{ width: 93.5%; } .contents_box{ display: flex; flex-direction: column; /* 세로 배치 받도록 한다 */ align-items: center; /* 왼쪽으로 치우쳐 지는 걸 방지 */ } .side_box{ /* 사이드 박스 숨기기 */ display: none; } .hidden_menu{ display: block; } } @media screen and (max-width:650px){ #header .search_box{ display: none; } .hidden_menu{ width: 95%; } }