<22.04.25> HTML/CSS/Javascript 활용하기 ㅡ School News 화면 반응형으로 구성하기
지난 크리스마스 카드 화면 구성에 이어 이번엔 School News 화면을 반응형으로 구현하는 내용을 포스팅한다. 구현할 페이지 화면은 아래와 같다.
위 시안을 대상으로 HTML과 CSS를 활용하여 화면을 구성할 것이다. 다만 실제로 받은 이미지 파일 중 몇가지가 다른 것이 있어, SNS 아이콘에는 차이가 있으며, 실제 사이트에서 제공했던 html 파일을 확인한 결과 위 디자인과는 조금 차이가 있음을 확인하였다. 따라서, 웹 브라우저에서 보이는 화면을 바탕으로 작업을 진행하였다.
아래는 실제 크롬에서 확인할 수 있는 화면이다.
iPhone SE와 iPad Mini 화면에 맞추어 화면을 구성하기로 한다. 파일 구조는 아래와 같다.
아주 간단하다. 폴더는 bootstrap과 image가 포함된 assets와, root폴더에는 실제 html 코드가 작성될 .html 파일과 style.css 파일, 그리고 디자인 시안이 포함되어있다.
0. HTML Head
<head>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1">
<link rel = "stylesheet" href = "./style.css">
<link rel = "stylesheet" href = "./assets/bootstrap/bootstrap-grid.min.css">
<link href="https://fonts.googleapis.com/css2?family=Akshar:wght@300;500;700&family=Roboto+Condensed:wght@300;400;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Akshar:wght@300;500;700&display=swap" rel="stylesheet">
</head>
반응형 웹페이지 제작을 위해 부트스트랩을 사용하였으며, Roboto-Condensed 폰트 적용을 위해 fonts.google에서 폰트를 다운받아 임포트하였다. 그리고 크리스마스 카드 화면 구성 때 사용하였던 Akshar 폰트도 필요한 것 같아 추가해주었다.
1. 페이지 구성
페이지 구성은 크리스마스 카드 화면 구성때와 동일하다.
1. header
2. main
3. footer
지난번과 같이 그림으로 설명하자면 아래와 같다.
총 3단으로 구성되는데, 각 단에 해당하는 HTML 코드는 아래와 같다. CSS 코드는 긴 관계로 github 주소로 대체하도록 하겠다. 순서대로 header, main, footer 코드이다.
<header>
<div class="container">
<div class="row">
<div class="col-12 header-logo">
</div>
</div>
<div class="row">
<div class="col-12">
<h1 class = "header-title">latest news</h1>
</div>
<div class="col-12">
<p class = "header-desc">
Stay in the loop. See what we're up to this month!
</p>
</div>
</div>
<div class="row">
<div class="col-12">
<img src = "./assets/image/hero.jpg" / class = "header-img">
</div>
</div>
</div>
</header>
<main>
<div class="container">
<div class="row">
<div class="col-12">
<h1 class = "main-title">what's new</h1>
</div>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class = "image-frame football-image"></div>
</div>
<div class="col-12 col-md-6">
<h1 class = "news-title">football season is here</h1>
<p class = "news-contents">
Support out team. Catch the football games this season at the campus field.
</p>
<button type = "button" class = "read-more-button">
read more
</button>
</div>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class = "image-frame dance-image"></div>
</div>
<div class="col-12 col-md-6">
<h1 class = "news-title">dance troupe auditions</h1>
<p class = "news-contents">
The dance troupe needs more members to join them as they perform for plays and other events this school year.
</p>
<button type = "button" class = "read-more-button">
read more
</button>
</div>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class = "image-frame fair-image"></div>
</div>
<div class="col-12 col-md-6">
<h1 class = "news-title">college fair</h1>
<p class = "news-contents">
Attend our annual get-togethers and make new friends.
</p>
<button type = "button" class = "read-more-button">
read more
</button>
</div>
</div>
</div>
</main>
<footer>
<div class="container">
<div class="row follow-box">
<div class="col-12">
<strong>
Follow us on our social media accounts
</strong>
</div>
<div class="col-12">
<ul class = "sns-list">
<li>
<a href = "#">
<img src = "./assets/image/facebook.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/google-plus.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/ig.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/pinterest.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/linkedin.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/twitter.png" />
</a>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="col-12">
<ul class = "footer-links">
<li>
<a href = "#">Privacy Policy</a>
</li>
<li>
<a href = "#">Terms Of Use</a>
</li>
<li>
<a href = "#">Contact Us</a>
</li>
<li>
<a href = "#">Manage Email Preferrences</a>
</li>
<li>
<a href = "#">Unsubscribe</a>
</li>
</ul>
</div>
</div>
</div>
</footer>
반응형 웹 페이지 제작을 위해 부트스트랩을 살짝 활용하였다. 특히 main 태그 속 뉴스 섹션을 나타내는 col들에 대해서 iPhone SE의 경우 col-12를, iPad Mini의 경우 col-md-6를 사용하였다. 이렇게 나눈 이유는, 화면이 커짐에 따라서 하나의 row에 여러 col을 넣어야 하는 상황이 있기 때문이었다. 그 외에는 크리스마스 카드 화면 구성 때와 크게 달라진 점은 없다.
하지만 HTML과 CSS를 작성하면서 그리 오래는 아니지만 어려움을 겪었던 부분들이 있었는데, 어려움이 있었던 부분과, 원인, 그리고 해결 방법에 대해 소개하겠다.
2. 잘 안되었던 점
2-1. 요소의 잘못된 배치
main 태그 부분을 작성하면서 main의 제목에 해당하는 'What's New' 부분에 margin이 먹지 않은 것인지, 다른 요소와 정렬을 맞추지 못했다.
WHAT'S NEW 부분이 혼자서 내어쓰기가 되어버렸다.. 실제 title부분을 꾸며주는 css 클래스 이름이 main-title이었다.
처음에는 margin-left의 값을 직접 주어서 다른 요소들과 수직 정렬을 맞추려고 했지만 근본적인 해결책은 아닌 것 같아 그만두었다.. 다 똑같이 부트스트랩 먹이고 body에 패딩도 먹이지 않았는데 왜 이런걸까.. 하고 HTML 태그를 자세히 본 결과 원인은 아래와 같았다.
.row까지 적어주고 .col-n 을 작성하지 않았다.. 그래서 부트스트랩이 제대로 작동하지 않아 .main-title이 따로 놀았던 것이다. 만약 이런 부분을 제대로 확인하지 않고 구글링만 죽도록 했다면 절대로 원인을 찾을 수 없었을 것이다. 아니면 margin-left 값을 주어 땜빵식으로 해결하였던지...
2-2. 의사 선택자의 잘못된 사용
main 태그의 내용을 작성하던 도중, 사진들의 간격을 띄우기 위해 margin-top을 설정하고 있었다. 그런데 위에서 설명하였던 .main-title과 사진의 간격은 좁은데 반해, READ MORE 버튼과 사진의 간격이 조금 넓은 탓에 사진에 적용할 css 클래스에 margin-top 값을 일방적으로 설정해줄 수가 없었다.
main-title과 사진 사이의 간격은 유지하되, read more 버튼과 바로 아래에 등장하는 사진 사이의 간격은 훨씬 넓어야 한다.
<main>
<div class="container">
<div class="row">
<div class="col-12">
<h1 class = "main-title">what's new</h1>
</div>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class = "image-frame football-image"></div>
</div>
<div class="col-12 col-md-6">
<h1 class = "news-title">football season is here</h1>
<p class = "news-contents">
Support out team. Catch the football games this season at the campus field.
</p>
<button type = "button" class = "read-more-button">
read more
</button>
</div>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class = "image-frame dance-image"></div>
</div>
<div class="col-12 col-md-6">
<h1 class = "news-title">dance troupe auditions</h1>
<p class = "news-contents">
The dance troupe needs more members to join them as they perform for plays and other events this school year.
</p>
<button type = "button" class = "read-more-button">
read more
</button>
</div>
</div>
<div class="row">
<div class="col-12 col-md-6">
<div class = "image-frame fair-image"></div>
</div>
<div class="col-12 col-md-6">
<h1 class = "news-title">college fair</h1>
<p class = "news-contents">
Attend our annual get-togethers and make new friends.
</p>
<button type = "button" class = "read-more-button">
read more
</button>
</div>
</div>
</div>
</main>
사진이 들어가는 태그에 image-frame이라는 class를 별도로 작성하였는데, 사진이 총 세 개 들어가니 세 번을 사용하였다. 그래서 첫번째 image-frame에만 margin-top을 10px를 주기 위해 아래와 같이 CSS를 작성하였다.
기존 image-frame에 대해서는 margin-top을 50px로 두어 read more 버튼과 간격을 넓히려고 하였지만, 처음으로 등장하는 image-frame의 경우 margin-top을 적게 두어 main-title과의 간격을 좁히려고 하였다. 하지만 결과는 달랐다. 크롬에서는 read more버튼과 사진과의 간격 또한 10px로 설정되었다. 어디가 문제인지 visual studio를 헤매고 있을 무렵.. 원인은 HTML 태그에 있었다.
나는 image-frame 클래스에 의사 선택자를 사용하여 처음 등장하는 image-frame 클래스에만 margin-top을 설정하고 싶었는데, 실제 작성한 HTML 태그를 확인하면, image-frame 클래스는 형제 관계가 아니다. 그래서 모든 image-frame 클래스에 margin-top이 10px로 설정되었다. 원인을 알고 나니 허파가 히뜩 뒤집어졌다... 선택자에 대해서 제대로 이해하지 못했구나... ㅠㅠ
그래서 위 CSS 코드를 아래와 같이 수정하였다.
main .row:nth-child(2) .image-frame {
margin-top: 20px;
}
첫 번째 image-frame에 해당하는 클래스를 선택하기 위해 위와같이 작성하였다. 그 결과 아주 잘 작동되었다.
2-3. <ul> 태그의 고정 padding값으로 인한 원하는 레이아웃 설정 불가능 문제
footer 태그를 작성하는 도중, SNS 이미지를 가운데로 정렬하던 도중 이상한 점을 발견했다. 우선 아래 코드를 보자.
<div class="container">
<div class="row follow-box">
...
<div class="col-12">
<ul class = "sns-list">
<li>
<a href = "#">
<img src = "./assets/image/facebook.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/google-plus.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/ig.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/pinterest.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/linkedin.png" />
</a>
</li>
<li>
<a href = "#">
<img src = "./assets/image/twitter.png" />
</a>
</li>
</ul>
</div>
</div>
위 코드는 footer에 있는 내용 중 SNS 이미지들을 표시하기 위한 HTML 태그들이다. li 요소는 default display가 block이기 때문에 한 라인에 모두 들어가지 못한다. 그래서 <ul>에 .sns-list 라는 class를 별도로 지정하여 아래 CSS 코드와 같이 flex를 부여해주었다.
위와 같이 작성하면 웹 브라우저에는 아래와 같이 출력된다.
크롬을 보고 열이 받았다. <li> 요소들을 감싸는 <ul> 태그에 flex를 부여하고 row로 지정하여 이미지들이 가로로 배치될 수 있게 지정하고, flex-start를 주어 ul의 가장 왼쪽에서부터 정렬될 수 있도록 했는데, 실제 개발자 도구에서 확인해보니 <ul> 태그 옆에 내가 지정하지도 않은 margin값이 포함되어 있는 것을 보고 당황했다.
그래서 <li> 요소 중 첫번째를 골라 margin-left값을 0으로도 줘보고, justify-content를 center로 지정해보기도 하고, <ul> 요소의 margin-left값을 0으로도 주고 별 짓을 다해보았지만 원하는대로 정렬이 되지 않았다. 구글신의 도움을 받은 결과 <ul> 태그는 본래 margin-left값을 가지고 있음을 알게 되었고, 이를 지우기 위해서 -webkit 속성을 주면 해결할 수 있음을 알게 되었다. webkit에 대해서는 다음에 한 번 포스팅 하도록 하겠다. 그 결과 아래와 같이 CSS 코드를 작성해주었다.
-webkit-padding-start는 요소에 기본적으로 지정되어있는 padding값을 설정할 수 있게 해준다. 이를 0px로 해주면 padding값이 사라져 원하는 대로 정렬이 가능해진다.
2-4. row내 모든 col이 포함되지 못하는 문제
반응형 페이지 제작을 위해 iPad Mini 사이즈에 맞추어 CSS 코드를 작성하던 도중, main 부분의 화면이 무너지는 것을 확인했다. 캡처하지 못했는데, 대충 설명하자면
위 화면에서 main 영역에 포함된 사진과 오른쪽 타이틀, 그리고 설명, read more 버튼이 위 화면과 같이 출력되지 않고, 설명 부분과 read more 버튼이 viewport를 벗어나는 문제가 발생했다. 아래는 iPad Mini 화면 제작 이전에 iPhone SE 화면을 구현중일 때 사용했던 HTML 코드이다.
WHAT'S NEW에는 세 개의 뉴스가 있다. 각 뉴스들은 하나의 row에 포함되어 있고, 하나의 row안에는 사진과, 뉴스 타이틀, 그리고 뉴스 컨텐츠라는 요소들이 하나의 col을 이루고 있다. 위 사진에는 나와있지 않지만, 각 col에 col-md-6를 삽입하여 iPad Mini 화면이 되었을 때 자동으로 viewport에 6개의 칼럼씩 차지하는 그림을 원했는데 그러지 못했다.
원인은 위 코드에 있었다. 뉴스 타이틀과 뉴스 컨텐츠, 그리고 read more 버튼이 모두 별개의 칼럼으로 설정되어 있는 바람에 서로의 영역을 가진 상태에서 한정된 viewport 내에서 자리를 차지해야 하니 레이아웃이 붕괴되었다. 그래서 사진이 들어가는 칼럼과, 사진에 대한 설명을 나타내는 칼럼 딱 두 가지만 설정하여 viewport내에서 12칸의 col을 6칸씩 양분할 수 있도록 설정하였다.
기존 .news-title과 .news-contents, .read-more-button이 하나의 col을 가지고 있던 것에 비해 위 코드는 세 개의 클래스가 하나의 col에 포함되어있다. 그 결과 크롬에서 아래와 같이 표시되었다.
이후 적절한 margin값 설정을 통해 원하는 레이아웃을 구성할 수 있었다.
3. 결과물
그 결과 아래와 같은 결과물이 나왔다.
화면 녹화는 윈도우10에 내장되어있는 기능으로 진행했다. gif로 했으면 좋았을 텐데.. 다음에 올릴땐 gif로 올려보겠다.
4. 느낀점
아래는 여태껏 포스팅한 연습 결과물이 담긴 깃허브 주소이다.
GitHub - wisberry2022/HCJpractice: HTMl/CSS/Javascript 연습
HTMl/CSS/Javascript 연습. Contribute to wisberry2022/HCJpractice development by creating an account on GitHub.
github.com
강의를 보고 따라하는 것이 아닌, 직접 반응형 화면을 정말정말정말 간단하게 만들어보았다. 반응형 화면을 구성한다는 것은, 초기에 레이아웃을 잡을 때는 가장 작은 화면을 중심으로 구현하는 것을 중심으로 하지만, 코드의 높은 가독성과 효율적인 유지보수를 위해 향후 구현할 화면에도 적용할 수 있도록 태그를 구성하는 것이 중요하다는 것을 깨달았다. 그렇지 않으면 나중에 다시 갈아엎어야 하니까..
다음에도 좋은 연습거리를 찾아 포스팅하도록 하겠다.
P. S 조잡한 글 읽어주셔서 감사합니다! 혹시나 틀린 정보가 있다면 과감한 지적(하지만 욕은 삼가해주시면 감사하겠습니다 ㅎㅎ) 부탁드립니다.