Instagram 레이아웃 cloning #3 Navbar

leitmotif·2021년 12월 9일
0

클론 코딩

목록 보기
3/4
post-thumbnail

개요

Instagram cloning 중, Navigation bar를 정리합니다.


CSS Idea

Nav bar는 가로로 정렬되며, 브라우저의 맨 위에 위치해야합니다.

로고 / 검색 / 버튼 총 3가지 영역으로 나뉘어집니다.

검색바에 데이터를 입력하면 위와 같은 플로팅 영역이 있습니다.

즉, 검색바는 column 형태로 정렬되는 독립된 영역이 되어야 합니다.

우측 버튼도 마찬가지입니다.

클릭시 아래에 플로팅 영역이 발생합니다.


#mainContainer #navContainer #navRowBar header{
    align-self:center;
    font-size:34px;
    flex:1 0 127px;
    font-family:'Billabong', sans-serif;
}

#mainContainer #navContainer #navRowBar header span{
    cursor:pointer;
}

로고는 텍스트로 작성했습니다.

특이한 점으로는 flex-basis를 사용한 것에 있는데,

인스타그램의 navigaion bar가 실제로 해당 수치를 사용합니다.

flex:[flex-grow][flex-shrink][flex-basis]

flex-grow는 flex container의 크기에 꽉 채울 것인지, 원래 크기만 유지할 것인지 정합니다.
flex-shrink는 위와 같은 기준에서 크기를 유지할지, 축소할지 결정하며
flex-basis는 flex container의 크기에서 얼만큼을 차지할지 결정합니다.

단지 인스타그램의 기준일 뿐, 만약 CSS를 따로 참고하지 않았다면

부모인 navContainer에서

justify-content:space-between

을 썼을지도 모르겠습니다.

align-self:center를 통해 부모인 flex container에서 column기준 중앙 정렬을 진행했습니다.


#mainContainer #navContainer #navRowBar #navRowBarSearch{
    align-self:center;
}

로고와 동일하게 column 중앙 정렬을 해준 모습입니다.

왜 여기서 flex를 사용하지 않고 column 방향으로 정렬하지 않는거야?

이것은 후술할 결과 영역에서 설명합니다.

input 태그

#mainContainer #navContainer #navRowBar #navRowBarSearch #navRowBarSearchInput #mainSearchInput{
    width:18.3vw;
    height:36px;
    background: rgba(var(--b3f,250,250,250),1);
    color: rgba(var(--f52,142,142,142),1);
    border: solid 1px rgba(var(--b6a,219,219,219),1);
    border-radius: 3px;
    font-size: 14px;
    font-weight: 300;
    cursor: text;
    padding-left:30px;
    transition:0.3s ease;
}

참조하는 태그가 미친듯이 길어집니다... SASS가 마렵습니다...

1. input은 브라우저의 크기에 따라 width가 달라진다.
2. focus 이벤트가 발생하면 돋보기가 가려지며, 커서가 왼쪽으로 이동한다.
3. focusout이 발생하면 돋보기가 다시 표시되고 커서가 원위치 된다.

돋보기 아이콘

#mainContainer #navContainer #navRowBar #navRowBarSearch #navRowBarSearchInput #searchIcon{
    position:relative;
    font-size:12px;
    color:#8d8d8d;
    top:0px;
    left:25px;
}

이미 부모가 세로 중앙 정렬이 되어있기에 relative를 설정하고

top을 건들일 필요없이 input에 겹치도록 적절히 left를 설정했습니다.

여기까지 CSS에선 크게 별 볼일이 없고, 중요한 건 엄밀히 input에 해당되는 영역과 결과 영역이 분리됐다는 것이 키포인트입니다.

결과 영역

#mainContainer #navContainer #navRowBar #navRowBarSearch #searchResultBox{
    position:absolute;
    top:45px;
    width:18.3vw;
    height:100%;
    min-height:180px;
    display:none;
}

뜬금없이 absolute를 쓰게 됐습니다.

이 부분에서 약간 헤맸는데, 그림을 그려보니 빠르게 이해되었습니다.

만약 Search 영역을 flex-direction:column으로 처리하게 되면

의도와 다르게 위처럼 해당 영역에 낑겨버리는 사태가 발생합니다.

따라서 오히려 감싸는 부모 요소는 세로 중앙 정렬만 되도록 두고

자식 요소를 통해 너비를 결정한 뒤, 각기 요소를 독립적으로 두는 것이 낫다고 판단했습니다.

width:18.3vw

검색 바와 결과 영역의 너비를 통일시킨 뒤,

height:100%;
min-height:180px;
display:none;

결과 영역은 아예 없을 수도 있고, 있을 수도 있기에 위와 같이 반응형으로 변경되도록 높이를 조정하고 focus 여부에 따라 display를 결정합니다.

검색 결과가 너무 많다면 다른 페이지로 보내자는 발상에 적용하진 않았지만

overflow-y:scroll

영역에 스크롤바가 생성되도록 overflow-y를 사용할 수 있을 것 같습니다.


Buttons

#mainContainer #navContainer #navRowBar #navBtns{
    align-self:center;
    flex:1 0 127px;
    font-size:25px;
}

#mainContainer #navContainer #navRowBar #navBtns #navBtnsBox{
    display:flex;
    flex-direction: column;
}

#mainContainer #navContainer #navRowBar #navBtns #navBtnsBox #navBtnsArea{
    display:flex;
    flex-direction:row;
    justify-content: flex-end;
}

버튼이 표시되는 영역은 또 다른 특징을 가집니다.

시작점에 있는 로고는 따로 처리를 해주지 않아도 부모가 flex-start이기에 상관이 없지만

버튼은 끝점에 붙기 때문에 flex-end 처리가 필요하며

이것은 버튼 클릭시 출력되는 modal에도 동일하게 적용되어야 합니다.

전체를 감싸는 #navBtns는 큰 특징이 없지만

'버튼은 끝점에 붙기 때문에 flex-end 처리가 필요하며
이것은 버튼 클릭시 출력되는 modal에도 동일하게 적용되어야 합니다.'

이 문제가 있기에 버튼 영역, 모달 영역을 아우르는 컨테이너는

column 방향으로 정렬되도록 만들고, 안쪽 영역에서 flex-end를 적용합니다.

#mainContainer #navContainer #navRowBar #navBtns #navBtnsBox #navBtnsFloatingBox{
    display:flex;
    flex-direction: column;
    align-self: flex-end;
    position:absolute;
    visibility: hidden;
}

#mainContainer #navContainer #navRowBar #navBtns #navBtnsBox #navBtnsFloatingBox.active{
    visibility: visible;
}

modal 영역의 틀입니다.

position:absolute

Modal 영역에는 Arrow와 FloatingArea 두 가지 요소가 있습니다.

각각 relative 속성을 가지면서 top을 설정하여 absolute 영역 내부에서 자유롭게 배치했습니다.

버튼이 클릭되면 .active가 토글되어 표시/미표시를 결정합니다.

그리고 align-self:flex-end를 사용해 버튼 영역과 위치를 맞추었습니다.

검색 바에서는 top,left를 사용했었는데
영역에 따라 변화무쌍할 수 있다는 점에서
마찬가지로 flex 중첩을 사용해 리팩토링하면 더 효율적일 것 같습니다.

absolute를 적용했기에 플로팅 전체 영역이 버튼 영역을 침범합니다.

따라서 버튼은 보이지 않는 영역에 덮인 상태가 되므로

플로팅된 상태에서는 다른 버튼을 클릭할 수 없게 됩니다.

이는 의도적인 것으로, 설명은 후술합니다.

#mainContainer #navContainer #navRowBar #navBtns #navBtnsBox #navBtnsFloatingBox #navBtnsArrowDiv{
    position: relative;
    width: 14px;
    height: 14px;
    top:35px;
    background: rgba(var(--d87,255,255,255),1);
    box-shadow: 0 0 5px 1px rgba(var(--jb7,0,0,0),.0975);
    border: 1px solid rgba(var(--f23,255,255,255),1);
    transform: rotate(45deg);
}

#mainContainer #navContainer #navRowBar #navBtns #navBtnsBox #navBtnsFloatingBox #navBtnsFloatingArea{
    position:relative;
    top:25px;
    width:256px;
    background: rgba(var(--d87,255,255,255),1);
    box-shadow: 0 0 5px 1px rgba(var(--jb7,0,0,0),.0975);
    border-radius: 6px;
    padding:4px 4px 4px 10px;
}

modal의 요소들은 absolute인 부모 영역 내부에서

relative 및 top을 이용해 배치했고, 이유는 아래와 같습니다.

영역 내부에서 관련성있게 움직이고 싶다 <- relative
arrow와 area는 약간 겹친 상태가 되어야 한다 <- top 값 조정

또한 각 버튼을 선택할 때마다 transform을 통해 화살표의 위치가 바뀌는데,

각각 static한 값을 사용해 연관성이 없어보이는 트릭이 된 점이 아쉽습니다.

차라리 맨 위 부모를 flex-end로 위치시키고
width만 static값으로 자식 요소에서 결정시킨 뒤, absolute로 top:0px로 
부모 태그 맨 위로 위치시키고
그 안에 column 방향으로 된 div를 넣으면 어땠을까? 란 생각이 있습니다.
<flexbox justify-content:flex-end>
 <section position:absolute, width:[static number], top:0px>
   <flexbox justify-content:space-between, flex-d:column>
     <flexbox flex-d:row>
       <navBtns/>
     </flexbox>
     <arrowModal/>
     <floatingArea/>
   </flexbox>
 </section>
</flexbox>
		// 유사 코드입니다! 머리 속에 생각나는 대로 작성.

다음에 navbar를 구현할 땐 위처럼 해보아야겠습니다.


ETC

플로팅 영역에서 예고한 논외의 영역, '가리개'입니다.

#hideContainer{
    position:fixed;
    width:100%;
    min-height:100%;
    z-index:10000;
    display:none;
}
#mainContainer #navContainer{
    width:100%;
    height:60px;
    position:fixed;
    display:flex;
    flex-direction:row;
    justify-content: center;
    background-color: rgba(var(--d87,255,255,255),1);
    border-bottom: 1px solid rgba(var(--b6a,219,219,219),1);
    z-index:10001;
}

hideContainer는 mainContainer와 함께 body 밑에 있습니다.

인스타그램에서 nav button을 클릭하면 화면에 있는 어떤 버튼도 클릭되지 않고 아무데나 클릭하면 플로팅이 사라지게 되어있습니다.

아하! 전체 화면에 보이지 않는 영역이 덮여져 있겠구나!

위와 같은 발상에 fixed와 z-index를 이용해 전체를 덮는 영역을 만들고

플로팅 영역이 발생할 때 display를 none에서 block으로 돌립니다.

다만 저는 로고나 검색 바는 이용할 수 있도록 하고 싶었기에

navigation bar의 우선순위를 1 올려주었습니다.

다만 버튼은 여전히 클릭하지 못하게 만들고 싶었는데

여기에서 앞서 언급한 position:absolute를 통해 영역을 위로 올려

클릭하지 못하게 만들었습니다.

각 버튼은 font-awesome에서 가져왔습니다.
각각 button으로 감싸고, 선택되지 않은 버튼은 disable시키는 방법도
고려하였으나, 그 경우 폰트 특성상 흐려지는 것을 확인해 폐기했습니다.

마무리

반응형으로 width가 바뀐다거나, 위치가 어그러지는 문제 덕분에

가장 고생을 많이 했던 파트입니다.

결론적으로 부모 요소는 그저 정렬에만 손대도록 하고

자식이 크기를 결정하도록 수정하니 이렇게 쉬운(?) 것이었나? 싶었습니다.

더불어 실시간으로 포스팅을 작성하면서 불필요한 CSS를 발견했습니다.

기록의 장점을 다시금 깨달으며... 다음 포스팅은 feed 영역입니다.

profile
제가 그린 것으로 하여금, 동기를 일으키는 개발자가 되고 싶습니다.

0개의 댓글