Instagram 레이아웃 cloning #1 Login

8563 단어 CSShtmlCSS

개요

인스타그램 클로닝을 진행해보며 많은 자기 반성을 하고 있습니다.

시맨틱부터 시작해서, 그동안 스스로 레이아웃을 잘못짜고 있었구나...

한편으로는 다음부턴 또 새롭게 만들 수 있겠다라는 기대가 있습니다.

#1은 로그인 화면입니다.


구현 화면

첫 번째 사진은 Full width일 때의 상태입니다.

두 번째 사진은 브라우저의 너비가 735px 이하가 되는 경우의 화면입니다.

CSS Idea

  1. Instagram은 고정된 배경 위에 창을 띄우는 느낌을 고수한다.
  2. 영역이 깔끔하게 떨어진다. margin, padding, font-size 등의 크기가 통일되어 있는 편으로 보인다.
  3. Wrapper -> Container -> Contents와 같은 방식같다.

개발자 도구로 살펴보면, 사소한 element라도 부모 element로 감싸주어 포지셔닝이 원활하도록 구성되어 있습니다.

그림으로 살펴본다면

1. main은 flex가 적용된다.
  -> 너비, 높이 100% 및 중앙 정렬이 된다.
  -> 즉, main안에 넣는 요소는 항상 브라우저 기준 가운데 정렬이 된다.
2. Article은 컨텐츠들을 감싸는 container 역할을 한다.
  -> flex로 row 방향으로 나열되도록 하며
  -> 각 컨텐츠는 section으로 한 번 더 감싼다.
3. ImgBox는 별도의 처리가 없으므로 
  -> background 속성으로 컨트롤하는 것으로 마무리한다.
4. LoginForm
  -> logo / input / hr / optionBtn / Register 영역으로 나뉜다.
  -> Register는 약간 띄워져있으므로
  -> logo,input...등등과 Register를 또 별개의 Wrapper로 나눈다.

하나하나 구획을 나눠 각각의 요소가 일종의 독립적인 개체가 되면서

마치 Stylesheet가 여러개가 된 느낌이었습니다.

예를 들면,

Article은 flex-direction이 row이지만
그 안에 있는 section인 LoginForm은 column으로 정렬시킵니다.

마치 하나의 페이지가 아닌 여러 개의 페이지를 조립하는 기분입니다.


JS Idea

  1. 브라우저의 너비에 따라 element를 표시/미표시한다.
  2. input에 따라 btn을 활성화하거나, 비활성화한다.
  3. 로그인, 페이스북 로그인, 비밀번호, 가입하기 등에 라우팅 함수를 걸어놓는다.

resize event

window.addEventListener('resize',function(event){
    const imgBox = document.querySelector('#imgBox')
    if (window.innerWidth<=735){
        imgBox.style.display='none';
    }else{
        imgBox.style.display='block';
    }
})

반응형으로 요소가 가운데로 오지 않는다거나.. 하는 상황이 있을 수 있기에

간단히 display 속성을 사용했습니다

display:none은 DOM에서 이 요소를 사라지게 하고
visibility:none은 단순히 눈에 안보일 뿐, DOM에는 남아있습니다.

input event

주어진 조건은 아래와 같습니다.

1. ID는 @가 포함되어야 한다.
2. Password는 5자 이상이어야한다.
3. 버튼 클릭뿐만 아니라 Enter키로 로그인할 수 있다.
inputID.addEventListener('input',function(event){
    if (event.target.value.includes('@') && inputPW.value.length>=5){
        loginBtn.style.backgroundColor='rgba(var(--d69,0,149,246),1)'
        loginBtn.style.cursor='pointer';
    }else{
        loginBtn.style.backgroundColor='rgba(var(--d69,0,149,246),.3)'
        loginBtn.style.cursor='inherit';
    }
})

inputID.addEventListener('keydown',function(event){
    if (event.key==='Enter'){
        if (inputID.value.includes('@') && inputPW.value.length>=5){

        }else{
            alert('ID, PW를 모두 입력해주시기 바랍니다.');
        }
    }
})

input 이벤트 발생시 event가 호출되도록 합니다.

react의 onchange와 같은 역할을 하지만
키워드는 'input'입니다. 잠깐 헷갈릴 요지가 있습니다 ㅜ.ㅜ

JS에서 키보드 입력은 'keydown'이 쓰입니다.

event.key를 호출하면 위와 같이 String형태가 나오며

event.keyCode를 호출하면 각 키의 코드가 출력됩니다.

이미 'Enter' String인 것을 알고 있었지만, 여러 다른 키가 필요하다면

콘솔로 미리 찍기엔 번거로우니 keyCode를 사용하는 것이 나아 보입니다.

1. input이 발생할 때마다 유효성 체크를 진행합니다.
2. 조건이 충족되지 않으면
  2-1. 로그인 버튼을 흐리게 만들고 
  2-2. 로그인 버튼의 클릭 커서를 비활성화합니다.
3. 조건이 충족되면
  3-1. 로그인 버튼을 명확하게 만들고
  3-2. 로그인 버튼의 클릭 커서를 활성화시킵니다.
4. input 태그에서 keydown 이벤트가 발생하면
  4-1. 'Enter'인지 식별하고
  4-2. 맞다면 유효성 체크 후
  4-3. 조건이 충족되면 서버와 통신하여 인증 절차를 거치고
  4-4. 조건이 충족되지 않으면 alert를 발생시킨다.

4-3의 경우, 아직 인증 api가 없으므로 빈 자리로 두었습니다.

4-4는 alert를 발생시키든, modal을 따로 정의해서 출력시키든 마음대로!

inputPW는 ID와 로직이 동일하므로 생략합니다.

routing Buttons

const loginFunc = () =>{
    if (inputID.value.includes('@') && inputPW.value.length>=5){
        // 서버로 입력값을 전달한다.
        // 서버의 응답에 따라 메인으로 이동하거나, alert를 발생시킨다.
    }
}
const forgetPWFunc = () =>{
    // 비밀번호 찾기 페이지로 라우팅한다.
}
const facebookLoginFunc = () =>{
    // 페이스북 로그인 modal를 출력한다.
}

앞서 서술했듯 api가 아직 없으니 작성하진 않았지만

예시를 들면

axios.post('/api/loginProgress',{id:inputID.value, pw:inputPW.value}
.then(response=>{
  if (response.data.status){
    window.location.href='/main'
  }else{
    alert('로그인 정보가 일치하지 않습니다.')
    window.location.href='/'
})

loginFunc()에는 위의 코드 같은 것이 들어올 수 있고

forgetPWFunc()는 단순히 비밀번호를 찾는 페이지로 라우팅되도록, 즉
fetch 등의 함수는 필요 없을 겁니다.

facebookLoginFunc()는 facebook 로그인 API를 통해 인증을 거칠 것입니다.

html에서는 간단하게

<input id='inputID' type='text' onclick='loginFunc()'>

위와 같이 event에 따른 함수 호출을 태그에 삽입해주었습니다.

ETC

label floating

실제 인스타그램에서는 ID, PW를 입력하면 placeholder가 플로팅됩니다.

구현한 화면은 그것이 적용되어 있진 않지만, 정리해보면

<label id='inputPlaceholder'> 입력해주세요! </label>
<input id='inputTag' type='text'>
#inputPlaceholder{
  position:absolute;
  ~ 이하.. top left right bottom 등 사용..
  left:14px; // 시작점에 위치..
  font-size:14px;
  font-weight:600;
  transition:0.5s ease; // animate를 0.5초간 smooth처리
}
#inputTag{
  padding-top:5px;   // 플로팅 위치를 비워줌...
  padding-left:14px; // 커서 위치를 옮김..
}
inputTag.addEventListener('input',function(){
  if (inputTag.value.length>0){
    inputPlace.style.fontSize:10px;
  }else{
    inputPlace.style.fontSize=14px;
}

위와 같은 느낌으로 해주면 될 것 같습니다.

기존과의 차이점이라면, label이라는 태그가 마치 placeholder처럼

보이게끔 css를 적용해주며, input에 이벤트를 달아서

placeholder 글자가 input 태그 내부에서 위로 올라가는 느낌으로 CSS를 만져주는 것입니다.

속성을 이용하는 게 아니라, 그냥 단순한 트릭의 일종인 것입니다.

최종 animate 화면


key points

1. 사소한 element라도 부모 요소를 만들면 포지셔닝이 편하다.
2. relative -> absolute로 짜게되는 경우
  2-1. absolute의 배치가 명확하다면 상관없지만
  2-2. 그렇지 않다면 element의 포지션이 꼬일 수 있다.
3. flex.. 이거 치트키일지도?

마무리

#2는 로그인 후 나타나는 페이지에 대한 설명입니다.

flex의 범람(?!)이 펼쳐지는데,

absolute를 애용했던 저는 이렇게 날로 먹어도 되나?! 하고 있습니다 😂

좋은 웹페이지 즐겨찾기