フロントのみで簡単なログイン機能を作る

## はじめに
javascriptとhtml、cssを使って簡単なログイン機能を書いてみました。


## ファイル構成
```
login |--html
      |     |
      |     |--login.html
      |     |--profile.html
      |     |--create-account.html
      | 
      |--app.js
      |  
      |--styles.css

```







## HTML







### login.html
```
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ログイン</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h2>ログイン</h2>
        <form id="loginForm">
            <input type="email" id="email" placeholder="メールアドレス" required>
            <input type="password" id="password" placeholder="パスワード" required>
            <button type="submit">ログイン</button>
        </form>
        <p>アカウントをお持ちでない方は <a href="create-account.html">新規アカウント作成</a></p> <!-- ここを修正 -->
    </div>

    <script src="app.js"></script>
</body>
</html>
```
### profile.html
```
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ユーザープロフィール</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h2>ようこそ、<span id="displayName"></span>さん</h2>
        <img id="displayIcon" alt="ユーザーアイコン" style="width:100px;height:100px;">
    </div>

    <script src="app.js"></script>
</body>
</html>
```








### create-account.html
```
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>新規アカウント作成</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h2>新規アカウント作成</h2>
        <form id="accountForm">
            <input type="email" id="newEmail" placeholder="メールアドレス" required>

            <input type="password" id="newPassword" placeholder="パスワード" required>

            <input type="text" id="username" placeholder="ユーザー名" required>

            <input type="file" id="userIcon" accept="image/jpeg" required>

            <button type="submit">アカウント作成</button>
        </form>
    </div>

    <script src="app.js"></script>
</body>
</html>
```







## CSS

### styles.css

```
/* 基本設定 */
body {
    font-family: 'Poppins', sans-serif;
    background-color: #f5f5f5;
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

/* コンテナのスタイル */
.container {
    width: 100%;
    max-width: 350px;
    padding: 30px;
    background-color: white;
    border-radius: 10px;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
    text-align: center;
}

/* 見出しスタイル */
h2 {
    margin-bottom: 20px;
    font-size: 1.5rem;
    color: #333;
    font-weight: 600;
}

/* 入力フィールドのスタイル */
input[type="email"],
input[type="password"],
input[type="text"],
input[type="file"] {
    width: 80%;
    max-width: 280px;
    padding: 12px 15px;
    margin: 10px 0;
    border: 2px solid #ddd;
    border-radius: 8px;
    background-color: #f9f9f9;
    font-size: 1rem;
    transition: border 0.3s, background-color 0.3s;
}

/* フォーカス時のスタイル */
input[type="email"]:focus,
input[type="password"]:focus,
input[type="text"]:focus {
    border-color: #b654c5;
    background-color: white;
    outline: none;
    box-shadow: 0 0 5px rgba(0, 123, 255, 0.5);
}

/* ボタンのスタイル */
button {
    width: 80%;
    max-width: 280px;
    padding: 12px;
    background-color: #b654c5;
    color: white;
    font-size: 1rem;
    font-weight: 600;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 0.3s, box-shadow 0.3s;
}

/* ボタンホバー時のエフェクト */
button:hover {
    background-color: #b654c5;
    box-shadow: 0 4px 12px rgba(0, 91, 179, 0.2);
}

/* リンクのスタイル */
p a {
    color: #b654c5;
    text-decoration: none;
    font-weight: 600;
    transition: color 0.3s ease;
}

p a:hover {
    color: #b654c5;
}

/* ユーザーアイコンのスタイル */
#displayIcon {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    object-fit: cover;
    margin-top: 10px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}

/* レスポンシブ設定 */
@media (max-width: 768px) {
    .container {
        width: 90%;
    }
}
```








## JavaScript









### app.js

```
// ログインフォームの処理
if (document.getElementById('loginForm')) {  //HTMLの'loginForm'を確認
    document.getElementById('loginForm').addEventListener('submit', function(e) {  //'loginForm'があった場合のイベントを追加
        e.preventDefault();                 //デフォルトの動作をキャンセルする
        const email = document.getElementById('email').value;  //ユーザーが入力したemailを取得
        const password = document.getElementById('password').value;  //ユーザーが入力したpasswordを取得

        const storedEmail = getCookie('email');    //クッキーに保存されたemailを取得
        const storedPassword = getCookie('password');    //クッキーに保存されたpasswordを取得

        if (email === storedEmail && password === storedPassword) {   //ユーザーが入力したemailとpasswordがクッキーに保存されている情報と一致しているか確認
            window.location.href = 'profile.html';  //一致している場合profile.htmファイルに移動
        } else {
            alert('Incorrect email or password');  //一致していない場合アラートが表示
        }
    });
}

// アカウント作成フォームの処理
if (document.getElementById('accountForm')) {    //HTMLの'accountForm'を確認
    document.getElementById('accountForm').addEventListener('submit', function(e) {     //'accountFormがあった場合のイベントを追加
        e.preventDefault();              //デフォルトの動作をキャンセルする

        const email = document.getElementById('newEmail').value;    //ユーザーが入力したemailを取得
        const password = document.getElementById('newPassword').value;    //ユーザーが入力したpasswordを取得
        const username = document.getElementById('username').value;    //ユーザーが入力したユーザー名を取得
        const userIcon = document.getElementById('userIcon').files[0];    //ユーザーが入力したアイコンを取得

        if (userIcon && userIcon.type === 'image/jpeg') {    //ユーザーがアップロードしたアイコンがjpegか確認
            const reader = new FileReader();      //画像を読み込む
            reader.onload = function(e) {     //読み込みが終えたら実行する処理（クッキーに保存）
                setCookie('email', email, 7);     //ユーザーが入力したemailをクッキーに保存
                setCookie('password', password, 7);     //ユーザーが入力したpasswordをクッキーに保存
                setCookie('username', username, 7);     //ユーザーが入力したをユーザー名クッキーに保存
                setCookie('userIcon', e.target.result, 7);     //ユーザーが入力したアイコンをクッキーに保存
                alert('Account created successfully');     //アカウントが作成されたことを表示
                window.location.href = 'login.html';     //アカウント作成後login.htmlページにに移動
            };
            reader.readAsDataURL(userIcon);     //ユーザーがアップロードした画像データを使えるようにする
        } else {
            alert('Please upload a JPEG image');     //ユーザーがアップロードしたアイコンがjpegではなかったに場合エラー表示する
        }
    });
}

// プロファイルページでユーザー情報を表示
if (window.location.pathname.includes('profile.html')) {     
    const username = getCookie('username');     //クッキーに保存されたユーザー名を取得
    const userIcon = getCookie('userIcon');     //クッキーに保存されたアイコンを取得

    if (username && userIcon) {     //ユーザー名とアイコンが存在するか確認
        document.getElementById('displayName').textContent = username;     //クッキーから取得したユーザー名を表示
        document.getElementById('displayIcon').src = userIcon;     //クッキーから取得したアイコンを表示
    } else {
        window.location.href = 'login.html';     //クッキーに情報がない場合'login.html'ページに移動
    }
}

// Cookieを設定する関数
function setCookie(name, value, days) {     //クッキーを設定するための関数(ユーザー名, 値, 保存期間)
    const date = new Date();     //Dateオブジェクトを作成
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));     //クッキーの有効期限を設定
    const expires = "expires=" + date.toUTCString();     //クッキーの有効期限をexpiresに変換 //日時を文字列に変換
    document.cookie = name + "=" + value + ";" + expires + ";path=/";     //クッキーを作成(名前、値、有効期限、サイト全体で有効であることを指定)
}

// Cookieを取得する関数
function getCookie(name) {     //クッキーの名前を引数として受け取る
    const nameEQ = name + "=";     //クッキーの名前を作る
    const ca = document.cookie.split(';');     //クッキー全体を分割
    for (let i = 0; i < ca.length; i++) {     //各クッキーをループで確認
        let c = ca[i];
        while (c.charAt(0) === ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);     //クッキー名が一致するか確認
    }     //ループが終えてもクッキーが届かなかった場合nullを返す

    return null;
}

```