본문 바로가기
dev/javascript

[javascript] 자바스크립트 로그인 페이지 만들기 (login)

by 최연탄 2023. 4. 16.
728x90
반응형

참고: https://medium.com/swlh/how-to-create-your-first-login-page-with-html-css-and-javascript-602dd71144f1

이 포스트에서는 HTML, CSS,  JavaScript를 사용하여 로그인 페이지를 만드는 방법을 알아보겠습니다. 스크립트를 작성하기 전에 먼저 무엇을 만들 것인지 보겠습니다:

로그인 페이지
로그인 성공
로그인 실패

보다시피 페이지에는 제목, 로그인 form(사용자 이름 및 비밀번호용), 입력 값을 제출하는 로그인 버튼이 있습니다. 이 예제에서는 사용자 이름이나 암호 확인을 위해 서버로 전송하지 않고, 대신 JavaScript를 사용하여 사용자 이름이 "user"이고 암호가 "web_dev"인지 확인합니다. 만일 이름과 암호가 일치하면 얼럿박스를 표시하고 페이지를 다시 로드합니다. 일치하지 않는 경우 오류 메시지를 표시합니다.

 최종 결과물을 확인했으니 스크립트 코드 부분으로 넘어가겠습니다.

HTML

먼저 페이지에 표시할 정보를 담당하는 HTML 부터 시작하겠습니다. 즉, 스타일(CSS)이나 상호작용(JavaScript)에 대한 걱정 없이 페이지에 포함된 모든 정보를 작성하고 구조화합니다.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Login</title>
  <link rel="stylesheet" href="login-page.css">
  <script defer src="login-page.js"></script>
</head>

<body>
  <main id="main-holder">
    <h1 id="login-header">Login</h1>
    
    <div id="login-error-msg-holder">
      <p id="login-error-msg">Invalid username <span id="error-msg-second-line">and/or password</span></p>
    </div>
    
    <form id="login-form">
      <input type="text" name="username" id="username-field" class="login-form-field" placeholder="Username">
      <input type="password" name="password" id="password-field" class="login-form-field" placeholder="Password">
      <input type="submit" value="Login" id="login-form-submit">
    </form>
  
  </main>
</body>

</html>

일반적인 HTML 파일과 같이 <head>와 <body>의 두 부분으로 구성합니다. 헤드는 사용한 문자 인코딩, 페이지 제목(브라우저 탭에 표시되는 이름), 이 HTML 파일이 사용할 CSS 및 JavaScript 파일에 대한 참조와 같이 웹 페이지의 메타 정보를 가집니다. HTML이 완전히 로드된 후에만 JavaScript 스크립트가 실행되도록 <script> 태그에 defer 속성을 넣었습니다.

<body>에는 페이지에 표시할 모든 정보가 포함됩니다. 단순한 <div> 대신 <main> 요소를 사용하여 페이지의 모든 콘텐츠를 래핑합니다. <main>은 의미적으로 다른 요소를 래핑한다는 점에서 <div>와는 기능적으로 동일하지만 브라우저에 웹 페이지 콘텐츠에 대한 더 많은 정보를 제공합니다. 예를 들어 스크린 리더와 같은 유틸리티의 작업을 용이하게 하고 웹 접근성을 높이는 데 필수적입니다.

<main> 요소, 즉 흰색 직사각형 내부에는 화면에 표시되는 모든 정보가 있습니다. <h1> 요소인 "로그인" 제목, 오류 메시지에 필요한 공간을 설정하는 <div>(<p>) 그리고 마지막으로 로그인 양식인 <form>입니다. 이 양식은 사용자 이름을 위한 텍스트 필드, 암호를 위한 암호 필드 및 각각의 양식 제출 버튼의 세 개의 <input> 요소로 구성되어 있습니다. 두 번째 필드의 type으로 password를 사용하는 것은 사용자가 암호를 입력할 때 실제 암호 대신 점으로 표시되도록 하는 것이 중요합니다. 또한 placeholder 속성에 유의하십시오. 해당 속성의 값은 양식 필드의 placeholder 텍스트로 표시됩니다.

그런데 왜 <input> 요소를 닫지(</input>) 않는지 궁금할 것 입니다. 왜냐하면 input은 닫는 태그가 필요하지 않습니다. 이를 self-closing 태그라고 합니다.

물론 CSS 작업을 용이하게 하기 위해 ID와 클래스를 많이 사용합니다. ID를 사용하면 HTML 요소를 명확하게 선택할 수 있습니다. 즉, 각 ID는 단일 요소를 나타냅니다. 반면에 클래스는 여러 요소에 대해 반복하려는 CSS 스타일 세트가 있을 때 사용합니다. 다음은 ID와 클래스의 실제 사용을 알아보겠습니다.

CSS

html {
  height: 100%;
}

body {
  height: 100%;
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
  display: grid;
  justify-items: center;
  align-items: center;
  background-color: #3a3a3a;
}

#main-holder {
  width: 50%;
  height: 70%;
  display: grid;
  justify-items: center;
  align-items: center;
  background-color: white;
  border-radius: 7px;
  box-shadow: 0px 0px 5px 2px black;
}

#login-error-msg-holder {
  width: 100%;
  height: 100%;
  display: grid;
  justify-items: center;
  align-items: center;
}

#login-error-msg {
  width: 23%;
  text-align: center;
  margin: 0;
  padding: 5px;
  font-size: 12px;
  font-weight: bold;
  color: #8a0000;
  border: 1px solid #8a0000;
  background-color: #e58f8f;
  opacity: 0;
}

#error-msg-second-line {
  display: block;
}

#login-form {
  align-self: flex-start;
  display: grid;
  justify-items: center;
  align-items: center;
}

.login-form-field::placeholder {
  color: #3a3a3a;
}

.login-form-field {
  border: none;
  border-bottom: 1px solid #3a3a3a;
  margin-bottom: 10px;
  border-radius: 3px;
  outline: none;
  padding: 0px 0px 5px 5px;
}

#login-form-submit {
  width: 100%;
  padding: 7px;
  border: none;
  border-radius: 5px;
  color: white;
  font-weight: bold;
  background-color: #3a3a3a;
  cursor: pointer;
  outline: none;
}

이제 CSS, 즉 페이지의 스타일을 갖게 되었습니다. HTML 파일의 각 요소를 수정하려면 ID, 클래스 또는 태그 이름 자체를 사용할 수 있는데 태그를 사용하는 것은 권장하지 않습니다. 보다 구체적으로 기술한 CSS selector는 덜 구체적인 스타일을 덮어씁니다. 예를 들어 id 선택자의 스타일은 클래스 선택자의 스타일을 덮어쓰고 클래스 선택자의 스타일은 태그 이름 선택자의 스타일을 덮어씁니다. 즉, 영향을 주고자 하는 요소에만 영향을 미치도록 항상 CSS selector를 가능한 한 구체적으로 만드십시오.

태그 이름 선택자는 태그의 이름만 있으면 되지만 id 선택자는 샵 기호(#)로 시작하고 클래스 선택자는 점(.)으로 시작합니다. 요소에 id "test-id"가 있는 경우 #test-id를 사용하여 CSS에서 해당 id를 선택할 수 있습니다. 요소에 "test-class" 클래스가 있는 경우 .test-class로 식별할 수 있습니다.

앞에서 태그 이름을 선택자로 사용하는 것을 지양하라고 했지만 여전히 태그 이름 선택자를 사용할 수 있습니다. 예를 들면 위 코드의 시작 부분을 살펴보십시오. <html> 및 <body> 태그 이름을 선택자로 사용했습니다. 이는 HTML 파일에는 이 두 요소가 각각 하나씩만 있기 때문입니다. 위의 경우 처음 두 ruleset(선택자와 대괄호 안의 모든 항목)를 사용하여 페이지 전체를 수정했습니다. <html> 및 <body> 높이를 100%로 설정하면 페이지가 화면 전체를 사용하고 <body> margin을 0으로 설정하면 이 요소의 기본 스타일로 인해 나타날 수 있는 수직 스크롤이 제거됩니다.

<body>에서 grid display를 사용하여 콘텐츠를 수직 및 수평으로 중앙에 배치합니다(각각 align-items 및 justify-items 사용). 즉, <main> 요소의 부모인 <body>의 내용을 가져와서 <main>과 그 내용을 화면 정중앙에 배치합니다. 이것을 CSS grid layout이라고 하며 자세한 내용을 간단히 설명하겠습니다.

우리는 간단히 grid layout 즉, grid display를 사용하도록 만든 다음 그에 따라 콘텐츠를 배치했습니다. 가능하다면 grid layout을 사용하는걸 추천합니다. 이는 페이지에 요소를 배치하는 간단하지만 강력한 도구입니다.

id main-holder(위 코드의 15행)에 의해 <main>의 크기를 조정하고 스타일을 조정하여 어두운 배경에서 눈에 띄게 만듭니다. 또한 <h1>, <div> 및 <form>의 세 가지 요소인 콘텐츠의 위치 지정을 쉽게 하기 위해 <main>을 grid로 바꿉니다. 따라서 CSS는 각 요소에 대해 3행 그리드로 만듭니다. 즉, 흰색 직사각형을 3행 으로 나눴다고 생각하면 됩니다.

grid의 첫 번째 행인 제목은 그대로 유지합니다. 이는 중앙에 있는 main-holder의 중앙에 위치할 뿐입니다.

반면에 두 번째 행은 오류 메시지가 포함된 행과 오류 메시지 자체를 모두 변경해야 하므로 추가 작업을 합니다(26~49행). grid layout을 다시 한 번 사용하여 메시지를 두 번째 행 중앙에 배치하고 <div>가 해당 행의 사용 가능한 공간을 모두 차지하도록 합니다(기본적으로 <div>는 포함된 요소의 크기와 동일하므로 더 크게 만들려면 width와 height를 지정해야 합니다.

오류 메시지의 경우 크기와 스타일을 변경합니다. 처음에는 opacity가 0으로 설정되어 있어 보이지 않습니다. 이 값은 사용자가 잘못된 정보를 입력하면 JavaScript를 사용하여 변경합니다.

또한 오류 메시지의 반 정도를 다르게 표시합니다. HTML의 메시지 요소를 보면 다음과 같습니다.

<p id="login-error-msg">Invalid username <span id="error-msg-second-line">and/or password</span></p>

텍스트의 반을 감싸는 <span> 요소를 주목해야합니다. <span>은 요소의 텍스트 일부만 스타일 지정하려는 경우 유용합니다. 오류 메시지를 "Invalid username" 및 "and/or password"라는 두 줄의 텍스트로 분할하고 싶기 때문에 <span>의 display를 block으로 설정하여 후반부를 새 텍스트 줄로 표시합니다.(#error-msg-second-line {display: block;})

이제 <main> 그리드의 세 번째 행인 <form>의 ruleset으로 CSS를 마무리하면 됩니다(마지막까지 71행). 마지막으로 grid layout을 사용하여 <form>을 그리드로 바꿉니다. 하지만 우리는 ruleset인 #login-form에서 또 다른 grid 속성을 사용합니다. <form>은 <main> 요소의 grid 컨테이너의 grid 항목이므로 해당 grid 항목이 자체 행 내부에 어떻게 배치되어야 하는지 알 수 있습니다. 따라서 align-self: flex-start를 사용하여 행의 맨 위에 세로로 정렬되도록 합니다.

그런 다음 form 필드의 스타일을 지정합니다. 우리는 두 필드(사용자 이름과 암호)가 동일하게 보이길 원하기 때문에 두 요소에 지정한 클래스인 login-form-field를 선택하는 단일 ruleset를 만듭니다. CSS에서 반복적으로 사용하기 위해 id로 각 개별 요소를 선택하는 대신 단일 클래스의 CSS를 한 번 만든 다음 해당 클래스를 두 요소에 사용합니다.

스타일 수정의 경우 이 두 <input> 요소를 더 보기 좋게 만들기 위한 약간의 변경이 있습니다. placeholder 텍스트 스타일을 <input>의 스타일과 일치하도록 ::placeholder pseudo 요소를 사용하여 해당 placeholder의 색상도 변경합니다. 그러나 전체 placeholder에 적용되도록 ::placeholder {...}라고 작성하는 대신 .login-form-field 클래스가 있는 요소의 placeholder만 변경하도록 다음과 같이 지정합니다. .login-form-field::placeholder {...}. 다시 말하지만 CSS selector를 가능한 한 구체적으로 만들어야합니다.

마지막으로 로그인 버튼의 스타일을 더 보기 좋게 변경합니다. 버튼 위에 마우스를 놓으면 커서가 포인터로 바뀌는 cursor: pointer를 제외하고는 새로운 것은 없습니다.

이제 우리는 HTML을 만들었고 CSS도 만들었습니다. 이제 JavaScript를 만들 차례입니다.

const loginForm = document.getElementById("login-form");
const loginButton = document.getElementById("login-form-submit");
const loginErrorMsg = document.getElementById("login-error-msg");

loginButton.addEventListener("click", (event) => {
    event.preventDefault();
    const username = loginForm.username.value;
    const password = loginForm.password.value;

    if (username === "user" && password === "web_dev") {
        alert("You have successfully logged in.");
        location.reload();
    } else {
        loginErrorMsg.style.opacity = 1;
    }
});

먼저 JavaScript로 작업하는 데 필요한 모든 요소(로그인 양식, 로그인 버튼 및 로그인 오류 메시지)를 가져옵니다. 이는 document.getElementById 메서드를 호출하여 찾는 요소의 id를 전달합니다. 또한 이 세 변수의 값은 변경되지 않으므로, 즉 변수는 항상 정확히 동일한 요소를 참조하므로 세 변수를 모두 const로 선언합니다.

그런 다음 로그인 버튼에 대한 이벤트 리스너를 만듭니다. 즉, 로그인 버튼을 클릭할 때마다 "click" 이후에 정의된 기능이 실행됩니다. 이 함수는 버튼 클릭을 나타내는 마우스 이벤트인 event라는 매개변수를 전달합니다(이름을 event로 지정하는 것은 일종의 관례일 뿐이며 원하는 대로 바꿔도 됩니다).

함수는 로그인 버튼을 클릭하면 실행되는 기본 동작(양식 데이터 제출)을 방지하는 것으로 시작합니다. 이 데모에서는 데이터를 제출하지 않고 JavaScript를 사용하여 유효성을 검사하기만 하므로 제출을 방지하기 위해 event.preventDefault()를 사용합니다.

그런 다음 사용자 이름 및 암호 양식 필드에서 각각 사용자가 입력한 값을 가져옵니다. JavaScript 구문을 활용하여 loginForm 양식의 필드를 formElement.nameOfField로 선택할 수 있습니다. 여기서 formElement는 HTML <form>이고 nameOfField는 찾고 있는 <input> 요소의 name 속성에 지정된 값입니다. 선택한 필드의 값을 가져오려면 .value를 추가하기만 하면 됩니다. 예를 들어 사용자가 사용자 이름 필드에 "user01"을 입력한 경우 loginForm.username.value로 해당 값을 가져옵니다.

이제 마무리 작업입니다. 사용자가 로그인 버튼을 클릭할 때마다 form 필드에 입력된 모든 값을 검색합니다. 우리는 자격 증명으로 무언가를 해야 합니다. 그런 다음 if/else 블록을 작성하여 로그인 자격 증명이 유효한 경우 코드를 실행하고 유효하지 않은 경우 다른 코드를 실행합니다. 여기에는 조건이 있어야합니다. 해당 조건을 자격 증명의 실제 유효성 검사로 만들어 보겠습니다. 간단하게 해당 유효성 검사는 입력된 사용자 이름이 "user"이고 암호가 "web_dev"인지 확인합니다. JavaScript 구문에서 이는 다음과 같이 변환됩니다.

username === "user" && password === "web_dev"

여기서 &&는 "user"와 같은 사용자 이름과 "web_dev"와 같은 암호가 모두 필요함을 지정하는 AND 연산자입니다.

자격 증명이 실제로 유효한 경우 사용자가 성공적으로 로그인했다는 메시지와 함께 alert 상자를 표시하고 페이지를 다시 로드합니다. 여기서 사용자 이름이나 암호가 유효하지 않은 경우 로그인 오류 메시지(loginErrorMsg)의 opacity 속성을 변경하여 표시되도록 하고 사용자에게 자격 증명이 유효하지 않음을 알립니다. loginErrorMsg(loginErroMsg.styles)의 스타일에 접근한 다음 opacity 속성(loginErrorMsg.styles.opacity)에 접근하여 원하는 값으로 설정하여 JavaScript 내에서 이 CSS를 변경합니다. 1로 설정하면 오류 메시지가 완전하게 보여집니다.

이제 HTML, CSS 및 JavaScript로 생성된 완전한 기능의 로그인 페이지를 만들었습니다. 이는 애니메이션을 추가하거나 페이지 디자인을 변경하거나 Node.js, Java, PHP 같은 백엔드의 유효성 검사 서버를 만들어 개선할 수 있습니다.

관련 글

자바스크립트 getElementById 사용 방법

자바스크립트 이벤트 리스너 등록 (addEventListener)

반응형

댓글