대강 velog.io

sjowow·2021년 1월 4일
0

대강

목록 보기
3/3

* 대강 velog.io

HTML과 CSS로 velog.io를 따라하자. 대강.
2020년 초velog 디자인을 기준으로 작성 되었음
순수 HTML과 CSS만으로 작업을 한 것이기 때문에 매우 불편 할 수 있음

1. 시작


디자인 카피에 무조건 해야 하는 것은 대상물을 관심 있게 뚫어져라 보는 것이다. 하지만, 대강 만드는 것이니 이미지 한 장으로 끝내자.

2. Layout


velog의 디자인 같은 경우 삼단 그리드의 익숙한 레이아웃을 사용하고 있다. 이 경우 레이아웃을 잡을 때 정말 많은 방법을 사용할 수 있는데 대표적으로 float position flex grid 네가지 방식을 쓸 수 있다. 또한, 왼쪽 컬럼의 경우 스크롤에 따라오게 되어 있으며, 중앙과 오른쪽 컬럼은 평범하게 스크롤을 할 수 있다.

2.1 Markup


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Copylog</title>
  </head>
	<body>
    <header>
      머리
    </header>
    <aside>왼쪽 메뉴 영역</aside>
    <main>포스팅 영역</main>
    <aside>
      오른쪽 태그 영역
    </aside>
  </body>
</html>

마크업의 경우 이 정도로 고정이 될 것 같다.

2.2 CSS


이제 css가 문제가 된다. 앞서 말한 것 처럼 다양한 방법으로 할 수 있기 때문에 어떻게 레이아웃을 잡을지 생각을 해봐야 하는데 이번에는 잘 사용한 적 없는 gird를 사용하여 잡아 보려고 한다. 하지만, 말 그대로 답이 없는 부분이기 때문에 하고 싶은 대로 대강 만들면 된다.

normalize

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css"
/>

일단, normalize를 추가하자.

grid

body{
	display: grid;
  grid-template-columns: 10rem auto 10rem;
	grid-gap: 1.25rem
} 

유지보수를 생각하면 body에 바로 그리드를 선언 하는 것 보단, div.wrapper 클래스를 만들어서 감싸주는 것이 좋다고 생각하지만, 대강하는 디자인 카피이기 때문에 body에다 선언한다. velog를 보면 중앙 컬럼만 너비가 변하고 양쪽 컬럼은 고정 너비라서 repeat 돌리지 않고 직접 선언을 해줬다. 만약, 전체가 반응형으로 변하고 중앙 컬럼의 너비는 양 옆 컬럼의 두배라는 룰이 있다면 4개의 grid를 만들고 중앙 컬럼을 2개의 컬럼을 차지하도록 해도 된다. grid-template-columns: 1fr 2fr 1fr도 가능한 방법 일 것이다.

grid-template-areas

body {
  display: grid;
  grid-template-columns: 10rem auto 10rem;
  grid-gap: 1.25rem;
  grid-template-areas:
    "header header header"
    "left-column main right-column";
}

자식들이 차지하고 있을 grid의 이름을 지정 해주자. 이 방법이 아니라 grid-column-start, grid-column-end등을 이용해서 잡는 방법도 있지만, 이게 좀 더 코드가 이뻐 보인다. 하지만 여기서 만약, grid-template가 등장한다면!?

grid-template

body {
  display: grid;
  grid-template:
    [row1-start] "header header header" [row1-end]
    [row2-start] "left-column main right-column" [row2-end] / 10rem auto 10rem;
  grid-gap: 1.25rem;
}

위와 같은 코드이지만 좀 더 간결하다!

grid-area

body > header {
  grid-area: header;
}
body > main {
  grid-area: main;
}
body > .left-column {
  grid-area: left-column;
}
body > .right-column {
  grid-area: right-column;
}

이제 body의 자식들이 미리 선언한 템플릿에 맞게 들어가도록 grid-area를 설정 해주자. 여기까지 작업 후 크롬의 개발자 모드로 해당 부분을 확인하면 다음 이미지와 같이 영역이 잡히면 레이아웃 성공!

3. Header


이제 상단 Header 모습을 잡아야 한다. 이제 여기서 부터 레이아웃 접근을 어떻게 하냐에 따라 방법이 달라질 수 있다. 현재 velog를 보면 왼쪽에는 로고, 오른쪽에는 기능성 버튼들이 양쪽 정렬이 되어있는데 이것을 두 개의 컬럼인지 아니면 컨텐츠 내용의 흐름이 양쪽 정렬인지 결정을 해야 한다.

3.1 양쪽 정렬


양쪽 정렬일 경우 flex 를 통하여 양쪽 정렬을 해주면 된다.

Markup

<header>
  <h1>velog</h1>
	<div class="right-column">
	  <a href="#">새 글 작성</a>
		<img src="https://media.vlpt.us/images/sjowow/profile/3adb7682-2b15-4a71-bae9-60d25e46e187/제목_없는_아트워크.PNG?w=120" alt="프로필 이미지">
	</div>
</header>

CSS

body > header {
	display: flex;
	grid-area: header;
	align-items: center;
	justify-content: space-between;
}

logo.wrapper 를 하나 만들고 난 뒤 headerflex로 선언하면 끝

3.2 두 개의 컬럼


일단 결론부터 말하자면 원하는 방식으로는 실패하였다. grid의 경우 이름을 지정 할 수 있어서 그걸 이용해서 약간 마크업을 간략하고 싶었다.

<header>
  <h1>velog</h1>
  <a href="#">새 글 작성</a>
	<img src="https://media.vlpt.us/images/sjowow/profile/3adb7682-2b15-4a71-bae9-60d25e46e187/제목_없는_아트워크.PNG?w=120" alt="프로필 이미지">
</header>
body > header {
  display: grid;
  grid-template: [row1-start] "header-left header-right" [row1-end] / auto;
  grid-area: header;
  align-content: center;
}
body > header h1 {
  grid-area: header-left;
}
body > header a {
  grid-area: header-right;
}
body > header button {
  grid-area: header-right;
}

headerheader-left, header-right라는 이름의 두 개의 컬럼을 만든 후 각 자식들의 위치를 직접 잡아서 하는 방식을 하고 싶었다. 이럴 경우 각 자식들은 원하는 컬럼으로 들어가지만, 문제는 자식들이 겹치게 되고 이것을 풀어주는 방법을 찾지 못했다. 그렇기 때문에 결국 div로 자식들을 감싼 후 처리를 해줘야 한다.

<header>
  <h1>velog</h1>
	<div class="right-column">
	  <a href="#">새 글 작성</a>
		<img src="https://media.vlpt.us/images/sjowow/profile/3adb7682-2b15-4a71-bae9-60d25e46e187/제목_없는_아트워크.PNG?w=120" alt="프로필 이미지">
	</div>
</header>
body > header .right-column{
	grid-area: header-right;
}

그래서 이 부분은 flex로 처리를 하는 방식으로 결정하였다.

3.3 꾸미기

header

body > header {
	grid-area: header;
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 0 1em;
	height: 4rem;
	-webkit-box-shadow: 0px 0px 8px 0px rgba(50, 50, 50, 0.2);
  -moz-box-shadow: 0px 0px 8px 0px rgba(50, 50, 50, 0.2);
  box-shadow: 0px 0px 8px 0px rgba(50, 50, 50, 0.2);
}

box-shadow 사용이 어려우면 generator의 도움을 받자.

logo

body > header h1 {
	color: #333;
	font-size: 1.5rem;
	font-style: italic;
}

새 글 작성

body > header .right-column {
	font-size: 0.825rem;
}

body > header .right-column a {
  display: inline-block;
  padding: 0.2em 1em;
  border: solid 1px #333;
  border-radius: 1em;
  color: #333;
  text-decoration: none;
  line-height: 2em;
  transition: ease 0.3s;
}
body > header .right-column a:hover {
  background-color: #333;
  color: #fff;
  transition: ease 0.3s;
}

프로필 이미지

button 같은 태그에서 한 가지 고민점이 있다. 이러한 상호동작을 하는 태그의 경우 각 브라우저 별 기본 컴포넌트 CSS 가 적용이 되어있다. 그래서 이 부분을 초기화 시켜줘야 하는데 두 가지 방법이 있다. appearance , all 두 가지 css 속성을 사용하면 된다. 아무런 생각없이 쓰려면 all을 쓰는것이 편할 수 있지만, 기본 정의된 CSS를 없애고 싶은 것이기 때문에 appearance를 사용 하였다. 또한, 브라우저 별 커서 모양이 다를 수 있으니 지정을 해줘야 한다.

body > header .right-column button {
  width: 2.5rem;
  height: 2.5rem;
  background-color: transparent;
  padding: 0;
	margin-left: 1em;
  border: solid 1px #efefef;
  border-radius: 50%;
  overflow: hidden;
  appearance: none;
	cursor: pointer;
	vertical-align: middle;
  -moz-appearance: none;
  -webkit-appearance: none;
}
body > header .right-column button img{
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

4. Left Aside

이제는 Left Aside 부분을 디자인 해야한다. 하지만, 먼저 작업을 해줘야 하는 부분이 있다. 바로 grid-template 로 만든 영역의 크기를 수정을 한다.

grid-template:
          [row1-start] "header header header" [row1-end]
          [row2-start] "left-column main right-column" [row2-end] / 20rem auto 20rem;

4.1 HTML

마크업 경우 탭 형식의 버튼과 검색을 할 수 있는 간단한 입력 양식 영역이 존재한다. 탭 버튼의 경우 나중에 js를 이용하여 클래스 바인딩 하여 클릭 된 탭의 디자인을 변경하는 방식으로 간단하게 처리 할 수 있지만, js 까지는 넣지 않는 작업이고 충분히 마크업과 css 만으로 처리 할 수 있는 부분이기 때문에 개인적으로 아래와 같은 마크업을 선호한다.

<aside class="left-aside">
  <input type="text" placeholder="검색어를 입력하세요.">
	<div class="contents-type">
	  <div>
	    <input type="radio" name="content-type" id="trending" checked>
	    <label for="trending">트렌딩</label>
	  </div>
	  <div>
	    <input type="radio" name="content-type" id="new">
	    <label for="new">최신</label>
	  </div>
		</div>
</aside>

4.2 CSS

왼쪽 영역의 css 작업을 할 때 색상, 간격, 너비 등의 부분들은 개인의 취향에 맞게 하면 되는 부분이기 때문에 따로 설명을 하지 않겠다. 하지만, 가장 눈여겨 볼 부분은 input:type="radio"label을 이용하여 탭 형식의 버튼을 만드는 방법이다.

간단한 설명을 하자면

  1. input + label 형식의 마크업
  2. input 의 경우 display:none
  3. input:type="radio"name 통일
  4. labelinputfor, id 통일

위와 같이 마크업을 했을 경우 label 을 클릭 했을 때 연결된 inputchecked 상태변화가 이루어진다. 그럴 경우 checkedinput의 인접 선택자를 이용하여 가장 가까운 label의 모습을 변경 해준다.

아래의 .contents-type 으로 선택되는 자식들이 그 와 같은 내용들이다.

body .left-aside{
  padding-left: 1rem;
}
body .left-aside input{
  width: 100%;
  padding: 0.5em 0.5em;
  font-size: 0.825rem;
  box-sizing: border-box;
}
body .left-aside .contents-type{
  margin-top: 1.5rem;
}
body .left-aside .contents-type > div input{
  display: none;
}
body .left-aside .contents-type > div label{
  position: relative;
  display: block;
  width: 100%;
  padding: 0.825rem;
  cursor: pointer;
  text-align: center;
  box-sizing: border-box;
}
body .left-aside .contents-type > div label:hover{
  background-color: #fafafa;
}
body .left-aside .contents-type > div input:checked+label{
  color: #29b480;
  background-color: #edfdf3;
}
body .left-aside .contents-type > div input:checked+label::before{
  position: absolute;
  content: ' ';
  top: 0;
  left: 0;
  width: 2px;
  height: 100%;
  background-color: #29b480;
}

그 결과 위와 같은 탭 버튼이 완성 된다.

마무리


갑자기 여기서 포스팅이 마무리가 되는 것에 이상함이 든다면.. 이상한 것이 맞다. 왜냐하면 이 글을 작성하기 시작할 때는 2020년 상반기 였다. 하지만, 이런 저런 이유로 다른 작업들을 하다보니 작업을 진행 할 수 없었고 그러다 다른 작업들이 끝나고 남아있는 포스팅 거리들 중 이 포스팅을 다시 작업하게 되었는데 하필 velog의 디자인이 변경 됐다.

그래서 이전 디자인이 남은 거라곤 맨 처음에 찍어놓은 한 장의 사진과 머리속에 남은 기억 밖에 없다 보니 추가적으로 작업을 하면서 흥미를 잃어버렸다. 하지만, 끝까지 완성을 할까 생각을 했지만, 이미 이 포스팅을 쓰면서 해보고 싶었던 grid는 사용을 해봤으며, input, label을 이용한 방법도 작성 하였고, 더이상 작업을 하면 단순 노동 그 이상의 가치를 느끼지 못하여 그만 마무리를 하게 되었다. 사실 굳이 더 흥미 거리를 찾자면 grid 레이아웃 상태에서의 scroll 관련된 부분이지만, 그만 여기서 포스팅을 마무리 하겠다.

Full Code

전체 코드가 궁금하신 분들을 위해 남겨놓습니다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Copylog</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.css"/>
    <style>
      body {
        display: grid;
        grid-template:
          [row1-start] "header header header" [row1-end]
          [row2-start] "left-column main right-column" [row2-end] / 20rem auto 20rem;
        grid-gap: 1.25rem;
      }
      body > header {
        grid-area: header;
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0 1em;
        height: 4rem;
        -webkit-box-shadow: 0px 0px 8px 0px rgba(50, 50, 50, 0.2);
        -moz-box-shadow: 0px 0px 8px 0px rgba(50, 50, 50, 0.2);
        box-shadow: 0px 0px 8px 0px rgba(50, 50, 50, 0.2);
      }
      body > header h1 {
        color: #333;
        font-size: 1.5rem;
        font-style: italic;
      }
      body > header .right-column {
        font-size: 0.825rem;
      }

      body > header .right-column a {
        display: inline-block;
        padding: 0.2em 1em;
        border: solid 1px #333;
        border-radius: 1em;
        color: #333;
        text-decoration: none;
        line-height: 2em;
        transition: ease 0.3s;
      }
      body > header .right-column a:hover {
        background-color: #333;
        color: #fff;
        transition: ease 0.3s;
      }

      body > header .right-column button {
        width: 2.5rem;
        height: 2.5rem;
        background-color: transparent;
        padding: 0;
        margin-left: 1em;
        border: solid 1px #efefef;
        border-radius: 50%;
        overflow: hidden;
        appearance: none;
        cursor: pointer;
        -moz-appearance: none;
        -webkit-appearance: none;
        vertical-align: middle;
      }
      body > header .right-column button img{
        width: 100%;
        height: 100%;
        object-fit: cover;
        object-position: center;
      }

      body > main {
        grid-area: main;
      }
      body > .left-column {
        grid-area: left-column;
      }
      body > .right-column {
        grid-area: right-column;
      }

      body .left-aside{
        padding-left: 1rem;
      }
      body .left-aside input{
        width: 100%;
        padding: 0.5em 0.5em;
        font-size: 0.825rem;
        box-sizing: border-box;
      }
      body .left-aside .contents-type{
        margin-top: 1.5rem;
      }
      body .left-aside .contents-type > div input{
        display: none;
      }
      body .left-aside .contents-type > div label{
        position: relative;
        display: block;
        width: 100%;
        padding: 0.825rem;
        cursor: pointer;
        text-align: center;
        box-sizing: border-box;
      }
      body .left-aside .contents-type > div label:hover{
        background-color: #fafafa;
      }
      body .left-aside .contents-type > div input:checked+label{
        color: #29b480;
        background-color: #edfdf3;
      }
      body .left-aside .contents-type > div input:checked+label::before{
        position: absolute;
        content: ' ';
        top: 0;
        left: 0;
        width: 2px;
        height: 100%;
        background-color: #29b480;
      }

      body .right-aside{}
      
    </style>
  </head>
	<body>
    <header>
      <h1>velog</h1>
      <div class="right-column">
        <a href="#">새 글 작성</a>
        <button type="button">
          <img src="https://media.vlpt.us/images/sjowow/profile/3adb7682-2b15-4a71-bae9-60d25e46e187/제목_없는_아트워크.PNG?w=120" alt="프로필 이미지">
        </button>
      </div>
    </header>
    <aside class="left-aside">
      <input type="text" placeholder="검색어를 입력하세요.">
      <div class="contents-type">
        <div>
          <input type="radio" name="content-type" id="trending" checked>
          <label for="trending">트렌딩</label>
        </div>
        <div>
          <input type="radio" name="content-type" id="new">
          <label for="new">최신</label>
        </div>
      </div>
    </aside>
    <main>포스팅 영역</main>
    <aside class="right-aside">
      오른쪽 태그 영역
    </aside>
  </body>
</html>
profile
소-개

0개의 댓글