ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [HTML & CSS] Google Clone (2) 내비게이션, 검색
    FrontEnd/CSS 2021. 2. 22. 18:22

    Google 페이지를 클론코딩하는 작업을 했다. 기능적인 부분은 무시하고 외양에만 집중했다.

    분량 이슈로 나머지는 아래쪽에서 마무리했다.

    2021/02/21 - [FrontEnd/Prep] - [HTML & CSS] Google Clone (1) Flex Container, 로고, footer


    [내비게이션] svg,  justify-content: flex-end;  vertical-align: middle;  inline whitespace

    내비게이션에는 Gmail, 이미지, 다른 기능 추가 로드, 로그인 버튼의 총 4가지가 필요하다. 그리고 화면 오른쪽에 정렬돼야 한다.

     

     

     

    전체 블록을 차지하는 div 안에 작은 div로 오른쪽 영역이 다시 한번 묶여있고,

     

     

    Gmail, 이미지가 한 묶음, 추가 로드버튼과 로그인이 각각 묶여있다.

     

     

    nav 태그 안에 div를 넣고, 그 안에 위의 div 2개를 구성한다.

    <nav>
      <div class="navContainer">
        <div class="service1">
          <div class="gmail"></div>
          <div class="imageSearch"></div>
        </div>
        <div class="service2">
          <div class="googleMap"></div>
          <div class="logIn"></div>
        </div>
      </div>
    </nav>

     

    SVG

    이제 여기에 텍스트를 입력해주려는데, googleMap이 이미지인 것 같다. 사진을 다운로드받으려고 열어보니 <svg> 태그로 되어있다.

    <svg class="gb_Xe" focusable="false" viewBox="0 0 24 24">
      <path d="M6,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM16,6c0,1.1 0.9,2 2,2s2,-0.9 2,-2 -0.9,-2 -2,-2 -2,0.9 -2,2zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"></path>
    </svg>

    MDN을 참조해서 svg가 벡터 그래픽을 다루는 마크업 언어고, path에서 도형을 그리도록 명령을 내린다는 걸 배웠다.

    developer.mozilla.org/ko/docs/Web/SVG/Tutorial/Paths

    당장 익혀서 사용하기에는 어려우니, 일단 path 개념을 이해한 걸로 만족하고 google의 path 값을 그대로 가져왔다.

    focusable은 :focus와 같은 기능을 하는 것 같고, viewBox는 svg의 속성으로 (min-x, min-y, width and height)를 받아서 사용자에게 보여줄 SVG 요소의 viewPort 크기(브라우저 뷰포트가 아니다)를 정한다.

    <nav>
      <div class="navContainer">
        <div class="service1">
          <div class="gmail"><a>Gmail</a></div>
          <div class="imageSearch"><a>이미지</a></div>
        </div>
        <div class="service2">
          <div class="googleMap">
            <a class="googleMapLink">
              <svg viewBox="0 0 24 24">
                <path d="M6,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM6,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM16,6c0,1.1 0.9,2 2,2s2,-0.9 2,-2 -0.9,-2 -2,-2 -2,0.9 -2,2zM12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,14c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,20c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z">
                </path>
              </svg>
            </a>
          </div>
          <div class="logIn">
            <a class="logInButton">로그인</a>
          </div>
        </div>
      </div>
    </nav>

     

     

     

    이게 무슨 일이람. 크기가 엄청나게 크게 나왔다.

    svg를 감싸는 a에 width와 height을 주고, svg 태그가 a에 맞게 줄어들도록 padding 및 box-sizing: border-box를 지정한다.

     

     

     

     

    .googleMap path {
      fill: #5f6368;
    }
    
    .googleMapLink {
      display: inline-block;
      width: 40px;
      height: 40px;
      padding: 8px;
      box-sizing: border-box;
    }

    구성요소 각각에도 색깔, 폰트, 배경, border 등을 지정해준다.

    .service1 {
      font: 13px/27px arial,sans-serif;
      color: rgba(0,0,0,0.87);
      line-height: 24px;
    }
    
    .logInButton {
      background-color: #1a73e8;
      border: 1px solid transparent;
      border-radius: 4px;
      box-sizing: border-box;
      color: #fff;
      cursor: pointer;
      display: inline-block;
      font: 500 14px "Google Sans", "Roboto","RobotoDraft", "Helvetica", "Arial", sans-serif;
      padding: 9px 23px;
      letter-spacing:.25px;
      line-height: 16px;
      min-width: 96px;
      text-align: center;
    }

    로그인 버튼은 border-box여서 padding값까지 박스 사이즈 안으로 들어가서, width를 넉넉하게 주었다.

    아마도 다른 요소들과 같이 정렬되어야 해서 너비 계산 측면 때문에 그런듯하다.

    버튼 크기 설정을 위한 padding을 주고나서, 이번에는 잊지 않고 display: inline-block 설정을 해주었다.

     

     

     

    justify-content: flex-end;

    이제 이걸 가로로 배열해야 한다. 개발자도구에서 부모태그를 살펴보니 flex, justify-content: flex-end;가 같이 지정되어 있다.

     

     

     

    flex-end는 flex container의 자식들을 컨테이너의 메인축 끝으로 보낸다고 한다. 직접 줘보니 오른쪽 끝으로 가서 붙었다.

     

     

    .navContainer {
    	display: flex;
    	justify-content: flex-end;
    }

     

    MDN의 해당 부분을 살펴보니,

    flex-end로 지정하면 flex 항목 행의 마지막 항목이 flex 컨테이너의 끝선에서 정렬된다고 한다.

    flex-direction 속성은 기본값이 row기 때문에 따로 지정하지 않으면 끝(main-end side)은 오른쪽이 된다.

     

     

    이제 오른쪽 정렬은 끝났으니, 각 service 박스 내부를 정렬해야 한다.

    먼저 Gmail, 이미지를 살펴보니 display가 inline-block이다.

     

    <div class="service1">
      <div class="s1 gmail"><a>Gmail</a></div>
      <div class="s1 imageSearch"><a>이미지</a></div>
    </div>

     

     

    한번에 주기 위해서 s1 클래스를 추가하고, inline-block 속성값을 부여했다.

    .s1 {
      display: inline-block;
    }

    마찬가지로 service2에 해당하는 구글맵 아이콘과 버튼에도 같은 작업을 해주었다.

    <div class="service2">
      <div class="s2 googleMap">
        <!-- 아이콘 부분 -->
      </div>
      <div class="s2 logIn">
        <a class="logInButton">로그인</a>
      </div>
    </div>

     

     

    .s1, .s2 {
      display: inline-block;
    }

     

     

    align-items: center;

    이제 가로세로 위치와 padding, margin 등 박스크기만 잡아주면 된다.

    먼저 전체를 감싸고 있는 nav와 navContainer에 패딩을 줘서 버튼 위치를 맞추고, align-items: center;를 줬다.

     

     

    nav {
      height: 60px;
      padding: 6px;
    }
    
    .navContainer {
      align-items: center;
      box-sizing: border-box;
      display: flex;
      height: 48px;
      justify-content: flex-end;
      padding: 0 4px 0 32px;
    }
    

     

     

    Gmail, 이미지가 정렬이 되긴 했는데 navContainer 내부에서만 align-items: center;이 돼서 위쪽으로 좀 기울었다.

    nav 높이가 60px이고 패딩이 6px면 48px니까 같아야 하는데 왜 navContainer와 nav의 높이가 다른가 생각해보니 nav에 box-sizing: border-box값을 안 줬다. 수정해주고 나니,

     

     

    Gmail, 이미지는 예쁘게 중앙 정렬이 됐다.

     

     

    vertical-align: middle;

    이제 버튼과 아이콘을 중앙 정렬해야 한다.

    다시 개발자도구를 살펴보니, 각각의 Gmail, 이미지, 아이콘, 버튼 요소들에 vertical-align: middle;이 부여되어 있다.

    vertical-align은 inline, inline-block 요소의 수직 정렬을 지정하는 프로퍼티라고 한다.

    middle은 부모의 baseline + x-height / 2로 정렬한다.

    .s1 a, .s2 a {
      vertical-align: middle;
    }
    

    a태그들을 수직정렬 했더니

     

     

    예쁘게 정렬되었다. 구글 페이지에 비해 좀 다닥다닥 붙어있으니 padding과 margin을 마저 준다.

    .service1 {
      display: block;
      padding-right: 15px;
    }
    
    .imageSearch, .gmail {
      padding-left: 15px;
    }

    그런데 구글 박스에 비해 service2 박스가 좀 작다. 구글 박스는 48px인데 내 박스는 40px.

     

     

     

     

     

    왜 그런가하고 살펴보니, 아이콘에서 너비/높이를 줄 때 a에 40px까지만 주고, 이걸 감싸고 있는 .googleMap에는 아무것도 안 줬다.

    패딩을 마저 주고, 버튼 옆의 공간이 좁으니 이쪽에도 마진을 추가해준다.

    .logInButton {
      margin: 0 8px;
    }
    
    .googleMap {
      padding: 4px;
    }

     

     

    inline whitespace

    나머지는 다 맞아졌는데 아이콘과 로그인 사이에 빈 공간이 있다.

     

     

    inline-block을 가로로 나열하면 예상치 못한 공백(4px 정도이 생긴다.

    CSS-TRICK의 fighting-the-space-between-inline-block-elements 페이지를 참고해서,

    html 태그가 분리되면서 (<inline1><inline2>가 아니라

    <inline1>

    <inline2>처럼 배열되면) 줄바꿈 문자와 공백이 생기게 된다는 걸 알았다.

    이걸 해결하는 몇 가지 방법이 있다. 괄호를 다음 라인에서 닫거나, 여백 부분을 주석처리해도 되고,

    음수 마진을 주거나 (-4px), 폰트사이즈를 0으로 설정해도 된다.

    아니면 대신에 float처리를 하거나, flexbox 레이아웃을 써도 된다고 한다.

     

    혹은 직접 치지말고 javacript로 DOM을 생성하면 이런 문제가 안 생긴다.

    JS로 생성하지 직접 HTML 태그를 입력해서 코딩할 일이 그렇게 많지는 않을 것 같아서, 이번에는 flex로 해결하고 넘어갔다.

    .service1, .service2 {
      display: flex;
      align-items: center;  /* 자식들이 block이 되면서 더 이상 vertical-align이 작동하지 않는다 */
    }

    이제 아래 코드는 필요없어졌다.

    .s1, .s2 {
      display: inline-block;
    }
    
    .s1 a, .s2 a {
      vertical-align: middle;
    }
    

     

     

    마지막으로 hover를 주면 된다.

    .service1 a:hover {
      text-decoration: underline;
      cursor: pointer;
    }
    
    .googleMapLink:hover {
      background-color: rgba(60,64,67,0.08);
      border-radius: 50%;
      cursor: pointer;
    }
    
    .logInButton:hover {
      background-color: #2b7de9;
      box-shadow: 0 1px 2px 0 rgba(66,133,244,0.3),0 1px 3px 1px rgba(66,133,244,0.15);
    }

     

     

     


    [검색] flex-basis, center

    검색도 크게 2부분으로 구성되어 있다. 검색어를 입력하는 바가 있고, 그 아래에 버튼이 두 개 있다.

     

     

    살펴보니 form으로 되어있다. 아래 버튼 두개는 submit이다.

     

     

    먼저 폼을 만든다. submit 부분은 center로 감싸져있길래 그대로 가져왔다. 중앙에 정렬해주는 태그라고 한다.

    <main class="search">
      <form action="/search" method="GET" role="search">
        <div class="searchBar">
          <div class="searchIcon">돋보기이미지</div>
          <input class="query" maxlength="2048" type="text">	
          <div class="typingLogo">키보드이미지</div>
        </div>
        <center class="submitContainer">
          <input type="submit" value="Google 검색">
          <input type="submit" value="I’m Feeling Lucky">
        </center>
      </form>
    </main>

     

     

    이미지를 구해야 하는데, 보니까 돋보기는 svg 이미지다. 그대로 가져오기로 하고, 키보드는 이미지 파일이 있다.

    각각 추가해주고, 위의 구글맵 같은 대왕 큰 이미지 사태를 방지하기 위해 CSS로 높이도 지정해준다.

    <div class="searchIcon">
      <svg viewBox="0 0 24 24">
        <path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
      </svg>	
    </div>
    
    <div class="typingLogo">
      <img alt="입력도구" src="https://www.gstatic.com/inputtools/images/tia.png">
    </div>
    .searchIcon svg {
      fill: #9aa0a6;
      height: 20px;
      width: 20px;
    }

     

     

    이제 중앙의 라운드형 검색어 입력창 모양을 만들어야 한다.

    .searchBar {
      background: #fff;
      border: 1px solid #dfe1e5;
      border-radius: 24px;
      height: 46px;
      margin: 0 auto;
      max-width: 584px;
    }

    row축 margin을 auto로 줘서 중앙에 위치하게 만들었다.

     

     

    이제 이 검색창 안에 아이콘들을 적절하게 배치해야 한다.

    먼저 block들을 가로로 정렬을 해야하니까, display: flex를 주고,

     

     

    인풋박스는 테두리 레이아웃을 없애고, 아이콘들을 가장자리로 배치해야 되겠다.

    .query {
      background-color: transparent;
      border: none;
      color: rgba(0,0,0,.87);
      flex-basis: 100%;  /* 전체를 차지해야 되기 때문에 100%를 주었다 */
      font-size: 16px;
      height: 34px;
      margin: 0;
      outline: none;
      padding: 0;
    }

    flex-basis는 flex item의 초기 크기를 지정하는 옵션이다. 100%를 주면 최대한으로 늘어난다.

     

     

    이제 나머지 아이콘들을 적당한 자리에 배치해주면 된다. 패딩과 마진을 이용하면 되겠다.

    .searchIcon {
      align-items: center;  /* 수직정렬 */
      display: flex;        /* 수직정렬 */
      padding-right: 13px;  /* 텍스트 입력부분 사이에 여백 주기 */
    }
    .typingLogo {
      align-items: center;  /* 수직정렬 */
      display: flex;        /* 수직정렬 */
    }

     

     

    아이콘이 중앙에 오긴했는데 아직 좀 치우쳐있다. 왼쪽, 오른쪽, 위쪽으로 여백이 더 필요할 것 같다.

    일단 타이핑 칸을 정렬한다. 그리고 로고들에 패딩을 추가해줬다.

    .searchBar {
      padding: 0 8px 0 14px;
      display: flex;        /* 수직정렬 */
      align-items: center;  /* 수직정렬 */
    }
    .typingLogo {
      padding: 0 8px;
    }

    정렬했을 때 부족한 부분은 margin과 패딩으로 맞췄다.

    보니까 구글은 키보드 아이콘을 감싼 div가 하나 더 있고, 그 컨테이너에 width: 24px이 들어있다.

    이미지의 width가 19px라서 5px만큼이 빈다. typing-logo의 padding에 부족한 5px만큼을 얹어줬다.

    여기 padding을 얹으면서 검색창 전체 크기가 커져서 box-sizing을 border-box로 바꿨다.

     

     

     

    이제 아래 버튼들에도 글꼴, 배경, 색깔 속성을 부여해줬다. (여기는 거의 복사 붙여넣기 수준으로 참조했다)

    .search input[type=submit] {
      background-color: #f8f9fa;
      border: 1px solid #f8f9fa;
      border-radius: 4px;
      color: #3c4043;
      cursor: pointer;
      font-family: 'Apple SD Gothic Neo',arial,sans-serif;
      font-size: 14px;
      height: 36px;
      line-height: 27px;
      margin: 11px 4px;
      min-width: 54px;
      padding: 0 16px;
      text-align: center;
    }

     

     

    이제 위아래 간격만 조정해주면 된다.

    .search {
      padding: 26px 18px 18px;
      width: auto;
    }
    
    .submitContainer {
      padding-top: 18px;
    }

     

     

     

    hover를 넣어주면 큰 레이아웃은 다 끝났다.

    .searchBar:hover {
      border: 1px solid #dadce0;
      box-shadow: 0 1px 6px rgba(32,33,36,.28);
      border-color: rgba(223,225,229,0);
    }
    
    .search input[type=submit]:hover {
      border: 1px solid #dadce0;
      box-shadow: 0 1px 1px rgba(0,0,0,.1);
    }

     


    나머지 부분들

     

    로고 높이 맞추기 height: calc(100% - 560px)

    본 페이지와 비교해보니 구글 로고가 어쩐지 좀 낮다.

    구글페이지는 화면이 일정 수준 이상 늘어나야 로고가 내려오기 시작하는데,

    내 화면은 스크롤이 생기지 않는 수준부터 바로 로고박스가 늘어나기 시작한다.

     

     

    왜 그런가하고 살펴보니 height: calc(100% - 560px);가 빠졌다.

    560px이란 수치는 상단 내비게이션 60px, 검색창 160px, 하단 푸터 98px을 주고,

    flex: grow: 1인 언어설정 부분은 높이가 가변적이므로, 이 부분이 242px까지 늘어난 다음부터 구글 로고를 이동시키겠다는 뜻인 듯하다.

     

    테스트해보면, 고정된 부분인 내비, 검색창, 푸터는 높이가 고정이고,

    언어설정부분이 242px가 되기전까지는 언어설정 박스가 먼저 늘어나서, 이 부분 높이가 242px이 되고 나면

    그때부터는 구글로고 박스 높이가 늘어난다. 구글로고 박스가 max-height인 290px에 도달하고 나면 다시 언어설정 박스가 늘어난다.

     

     

    거기에 맞춰서 height: calc(100% - 560px)를 주니

    .logo {
      display: flex;
      flex-direction: column;
      align-items: center;
      max-height: 290px;
      min-height: 92px;  /* 로고이미지 높이 */
      height: calc(100% - 560px);  /* 전체에서 560px를 제외한 길이만큼 지정 */
    }
    
    
    .logoWrapper {
    	margin-top: auto;
    	max-height: 92px;  /* height 지정을 안 하면 5px 정도 공간이 생긴다 */
    }
    

     

    화면 크기가 변하는 경우에도 로고의 높이가 맞아졌다.

     

     

    아래 Google 제공 서비스는 언어 상태에 따라서 나왔다가 안 나왔다가 하곤 한다.

     


    favicon 넣기

    이미지를 찾아서 link 태그로 넣어주면 된다.

    링크에 들어가는 rel 프로퍼티의 값은 shortcut icon 말고도 icon도 있고,

    type을 png, gif 등으로 명시해줄 수도 있다. 상세는 위키에 잘 나와있다.

    <link rel="shortcut icon" href="https://www.google.com/favicon.ico">
    <title>Google Clone</title>

     

     

     


    와 '는 다른 문자

    구글에 보면 I'm Feeling Lucky라는 버튼이 있다. 누르면 기념일을 다루는 Doodles 페이지로 연결된다.

     

    그런데 값을 아무리 똑같이 줘도 박스 크기가 가로 0.13 정도 차이가 나는 거다.

    아니 대체 왜그렇지? 하고 부모박스 패딩, 마진 온갖 걸 다 건드리면서 찾아봤는데도 못 찾다가

    Im Feeling Lucky

    I'm Feeling Lucky

    CSS 문제가 아니라 어퍼스트로피 때문임을 알게 됐다.

    아무리 명확해보이는 문자열이어도 직접 타이핑하기보다는 원문을 그대로 복사해오도록 해야겠다.

     

     

    댓글

Designed by Tistory.