認証 · ログインフォーム

グラスモーフィズムのログインモーダル

保存した一覧を見る 0 →

このブラウザー内に保存します。別の端末との同期はなく、サイトデータを消すと保存も消えます。

印刷時は見本を静止画にし、プロンプトと解説を出力します。PDF保存はブラウザーの印刷画面から選べます。

Vibehaus · デザイン資料
https://vibe.itlibra.com/design/glass-login-modal/
完全無料・著作権フリー(CC0)· 料金¥0 · 商用利用・改変自由

プレビュー

画面に合わせる

指定幅で実際に組み替えて表示します。表示領域より広い場合は、この枠の中で横へスクロールできます。

vibe.itlibra.com/preview/glass-login-modal/

AIへの指示文

モダンSaaSのトップ画面に被せるログインモーダルを作ってください。

要件:
- 背景はぼかしたカラフルな景観(暗めの紫〜青のメッシュ)。モーダル本体はガラス効果(backdrop-filter: blur(20px)、白透過1pxアウトライン)。
- モーダル幅 420px、角丸 24px、padding 36px。中央配置。
- 上部にロゴ(小さい)+ タイトル「ログイン」 + サブテキスト「アカウントにアクセスして続けます」。
- SSOボタン3つを横並び(Google / GitHub / Apple、ロゴアイコンのみの均等3分割ボタン)。
- 「OR メールで続ける」のセパレータ(左右に細い罫線)。
- メール入力 + パスワード入力(フローティングラベル)。
- 「パスワードを忘れた」リンクと、「ログイン」プライマリボタン。
- 下部に「アカウントをお持ちでないですか? 新規登録」のテキスト。
- フォントは Inter + Noto Sans JP。
- フルレスポンシブ。背景は装飾なので変化、モーダル幅はモバイル幅で 90% に。

バリエーション

passwordless 版

パスワード入力欄を廃止し、「メールにマジックリンクを送る」一発ボタンに変更。
セキュリティ補足を1行追加(「パスワード不要・15分で期限切れ」)。

2FA 入力ステップ版

ログイン後の2FA画面に遷移したUIに差し替え。6桁の数字入力フィールドを6個並列、
SMS or 認証アプリの選択タブ、再送リンクを下部に。

このプレビューのコード

HTML・CSS・JavaScriptの1ファイルです。外部依存・広告・解析コードはありません。ログイン画面の表示見本です。ダイアログの開閉・Escape・フォーカス復帰と必須項目・メール形式を試せます。認証・送信・保存は行わず、外部認証のボタンは説明だけを表示します。

CC0 · 改変・商用利用自由 · revision 5175583cfc3d

コードを表示
<!doctype html>
<!-- Vibehaus · CC0 · 架空のログイン表示見本。外部依存・送信・認証・永続保存なし。 -->
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="robots" content="noindex" />
    <title>グラスモーフィズムのログインモーダル — Vibehaus プレビュー</title>
    <style>
      :root {
        --ink: #f5f3ee;
        --muted: rgba(245, 243, 238, 0.7);
        --quiet: rgba(245, 243, 238, 0.5);
        --accent: #6c8aff;
        --glass-bg: rgba(20, 18, 30, 0.55);
        --glass-border: rgba(245, 243, 238, 0.18);
      }
      * { box-sizing: border-box; }
      html, body { margin: 0; padding: 0; height: 100%; }
      body {
        font-family: "Inter", "Noto Sans JP", "Hiragino Kaku Gothic ProN",
          "Yu Gothic", sans-serif;
        line-height: 1.7;
        -webkit-font-smoothing: antialiased;
        color: var(--ink);
        position: relative;
        background: #08071a;
        min-height: 100dvh;
        overflow: hidden;
      }
      /* Background mesh — purple/violet/blue */
      body::before {
        content: "";
        position: absolute;
        inset: -10vh -10vw;
        background:
          radial-gradient(35% 45% at 18% 22%, rgba(140, 80, 255, 0.55), transparent 70%),
          radial-gradient(40% 50% at 82% 18%, rgba(50, 100, 220, 0.5), transparent 70%),
          radial-gradient(45% 55% at 70% 88%, rgba(30, 200, 220, 0.35), transparent 70%),
          radial-gradient(30% 40% at 18% 82%, rgba(255, 80, 180, 0.28), transparent 70%);
        filter: blur(50px) saturate(1.2);
      }
      /* Background dim layer behind modal — softens any logos / hero behind it */
      .modal::backdrop {
        position: fixed;
        inset: 0;
        background: rgba(8, 7, 26, 0.35);
        backdrop-filter: blur(2px);
      }

      .center {
        position: relative;
        z-index: 5;
        min-height: 100dvh;
        display: grid;
        place-items: center;
        padding: 1rem;
      }

      .modal {
        width: min(420px, 100%);
        background: var(--glass-bg);
        border: 1px solid var(--glass-border);
        backdrop-filter: blur(28px) saturate(140%);
        -webkit-backdrop-filter: blur(28px) saturate(140%);
        border-radius: 24px;
        padding: 2.25rem 2.25rem 2rem;
        box-shadow:
          0 30px 80px -20px rgba(0, 0, 0, 0.5),
          inset 0 1px 0 rgba(255, 255, 255, 0.1);
      }
      .logo {
        display: inline-flex;
        align-items: center;
        gap: 0.5rem;
        margin-bottom: 1.5rem;
        font-weight: 700;
        font-size: 1rem;
        color: var(--ink);
      }
      .logo::before {
        content: "";
        width: 22px; height: 22px;
        border-radius: 6px;
        background: linear-gradient(135deg, #6c8aff, #c45fff);
      }
      .modal h1 {
        margin: 0 0 0.55rem;
        font-size: 1.7rem;
        font-weight: 700;
        letter-spacing: 0;
        line-height: 1.3;
      }
      .modal h1 :lang(ja) { letter-spacing: 0; line-height: 1.4; }
      .sub {
        margin: 0 0 1.75rem;
        font-size: 0.92rem;
        color: var(--muted);
      }

      /* SSO row */
      .sso {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: 0.6rem;
        margin-bottom: 1.5rem;
      }
      .sso button {
        display: grid;
        place-items: center;
        height: 48px;
        background: rgba(245, 243, 238, 0.06);
        border: 1px solid rgba(245, 243, 238, 0.12);
        border-radius: 12px;
        color: var(--ink);
        cursor: pointer;
        transition: background 0.2s, border-color 0.2s, transform 0.15s;
      }
      .sso button:hover {
        background: rgba(245, 243, 238, 0.1);
        border-color: rgba(245, 243, 238, 0.25);
        transform: translateY(-1px);
      }
      .sso svg { width: 22px; height: 22px; display: block; }

      /* Separator */
      .sep {
        display: flex;
        align-items: center;
        gap: 0.85rem;
        margin: 0 0 1.5rem;
        color: var(--quiet);
        font-size: 0.78rem;
        letter-spacing: 0.08em;
        text-transform: uppercase;
      }
      .sep::before, .sep::after {
        content: "";
        flex: 1;
        height: 1px;
        background: rgba(245, 243, 238, 0.14);
      }

      /* Inputs */
      .field {
        position: relative;
        margin-bottom: 0.85rem;
      }
      .field input {
        width: 100%;
        height: 48px;
        background: rgba(245, 243, 238, 0.04);
        border: 1px solid rgba(245, 243, 238, 0.14);
        border-radius: 10px;
        padding: 0.85rem 0.95rem 0.55rem;
        color: var(--ink);
        font-family: inherit;
        font-size: 0.95rem;
        outline: none;
        transition: border-color 0.2s, background 0.2s;
      }
      .field input:focus {
        border-color: var(--accent);
        background: rgba(245, 243, 238, 0.08);
      }
      .field label {
        position: absolute;
        top: 50%;
        left: 0.95rem;
        transform: translateY(-50%);
        color: var(--muted);
        font-size: 0.92rem;
        pointer-events: none;
        transition: top 0.15s, font-size 0.15s, color 0.15s;
      }
      .field input:focus + label,
      .field input:not(:placeholder-shown) + label {
        top: 0.5rem;
        font-size: 0.72rem;
        transform: none;
        color: var(--accent);
        letter-spacing: 0.04em;
      }

      .row {
        display: flex;
        justify-content: flex-end;
        margin: -0.25rem 0 1rem;
      }
      .row a {
        font-size: 0.82rem;
        color: var(--muted);
        text-decoration: none;
      }
      .row a:hover { color: var(--accent); }

      .submit {
        width: 100%;
        height: 50px;
        border: 0;
        border-radius: 12px;
        background: linear-gradient(135deg, #6c8aff, #c45fff);
        color: #08071a;
        font-family: inherit;
        font-size: 0.95rem;
        font-weight: 700;
        letter-spacing: 0;
        cursor: pointer;
        transition: transform 0.15s, box-shadow 0.2s;
        box-shadow: 0 8px 24px -6px rgba(108, 138, 255, 0.45);
      }
      .submit:hover {
        transform: translateY(-1px);
        box-shadow: 0 14px 32px -8px rgba(108, 138, 255, 0.55);
      }

      .signup {
        margin: 1.5rem 0 0;
        text-align: center;
        font-size: 0.88rem;
        color: var(--muted);
      }
      .signup a {
        color: var(--ink);
        text-decoration: none;
        font-weight: 600;
        border-bottom: 1px solid rgba(245, 243, 238, 0.4);
      }
      .signup a:hover { color: var(--accent); border-bottom-color: var(--accent); }

[hidden]{display:none!important}button,input{font-family:inherit}button:disabled{cursor:default;opacity:.7}
:focus-visible,.field input:focus-visible,input:focus-visible{outline:3px solid currentColor;outline-offset:3px}
.demo-note{margin-top:1.5rem;padding-top:1rem;border-top:1px solid currentColor;font-size:13px;line-height:1.8;letter-spacing:0;overflow-wrap:anywhere}
.demo-note h2{font-size:15px;line-height:1.5;letter-spacing:0}.demo-note p{letter-spacing:0;scroll-margin:1rem}
.demo-note a,a[href^="#demo-"]{display:inline-flex;align-items:center;min-height:44px}
.demo-status{font-size:14px;line-height:1.8;letter-spacing:0;overflow-wrap:anywhere;margin:1rem 0 0;padding:.65rem;border:1px solid currentColor;border-radius:8px}
.demo-caption{font-size:12px;line-height:1.8;letter-spacing:0}
.motion-toggle{font:inherit;color:inherit;background:transparent;border:1px solid currentColor;border-radius:8px;min-height:44px;padding:.4rem .65rem;cursor:pointer;font-size:12px;letter-spacing:0}
html:not(.demo-js) .float,html:not(.demo-js) .mascot,html[data-motion-paused] .float,html[data-motion-paused] .mascot{animation:none!important}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}

body{overflow:auto}body::before{position:fixed;inset:0;pointer-events:none}.center{padding:1rem}.demo-background{max-width:560px;position:relative}.demo-background h2{line-height:1.5}
.modal{position:fixed;inset:0;margin:auto;height:fit-content;max-width:calc(100vw - 2rem);max-height:calc(100svh - 2rem);overflow:auto;color:var(--ink);padding:2rem clamp(1rem,5vw,2.25rem)}
html:has(.modal:modal){overflow:hidden}.modal::backdrop{background:rgba(8,7,26,.55)}.close{position:absolute;right:10px;top:10px;width:44px;height:44px;background:transparent;color:inherit;border:1px solid var(--glass-border);border-radius:50%;font-size:24px;cursor:pointer}
.launch{font:inherit;min-height:44px;padding:.7rem 1rem;border:1px solid var(--glass-border);border-radius:12px;background:var(--glass-bg);color:inherit;cursor:pointer}.sso button{font-size:16px;font-weight:700;line-height:1.4;min-width:44px}.sep{letter-spacing:0;color:var(--muted)}
.field input{height:64px;padding:1.75rem .95rem .35rem;font-size:16px;line-height:1.4}.field label{line-height:1.4}.field input:focus+label,.field input:not(:placeholder-shown)+label{top:.4rem;font-size:.75rem;letter-spacing:0;color:#b8c8ff}
.row a,.signup a{min-height:44px}.modal .logo{margin-right:44px}.demo-status:focus{outline-offset:2px}
</style>
  </head>
  <body>
    <main class="center"><div class="demo-background"><h2>ログイン画面の見本</h2><p>架空のサービスの表示見本です。入力はこのページ内の確認だけに使い、外部送信・認証・登録・永続保存は行いません。配布HTMLはCC0・利用料¥0です。</p><button type="button" class="launch" data-demo-open hidden>ログインの見本を開く</button><noscript><p>JavaScriptが無効なため、入力とリンクの表示だけを確認できます。認証・送信は行いません。</p></noscript></div>
      <dialog class="modal" open aria-labelledby="modal-title" aria-describedby="modal-description">
        <button class="close" type="button" data-demo-close aria-label="ログインの見本を閉じる" hidden>×</button>
        <div class="logo">Spectra</div><h1 id="modal-title">ログイン</h1>
        <p class="sub" id="modal-description">架空の値で入力条件を確認する見本です。認証は行いません。</p>
        <div class="sso" role="group" aria-label="外部認証ボタンの表示見本">
          <button type="button" data-demo-provider="Google" aria-label="Googleでログインの見本" disabled>G</button>
          <button type="button" data-demo-provider="GitHub" aria-label="GitHubでログインの見本" disabled>GH</button>
          <button type="button" data-demo-provider="Apple" aria-label="Appleでログインの見本" disabled>A</button>
        </div><div class="sep">OR メールで続ける</div>
        <form method="dialog" novalidate autocomplete="off">
          <div class="field"><input type="email" id="email" placeholder=" " required autocomplete="off" /><label for="email">メールアドレス</label></div>
          <div class="field"><input type="password" id="pw" placeholder=" " required autocomplete="off" /><label for="pw">パスワード</label></div>
          <div class="row"><a href="#demo-reset">パスワードを忘れた?</a></div>
          <button class="submit" type="button" data-demo-submit disabled>入力条件を確認</button>
        </form>
        <p class="demo-status" data-demo-status role="status" tabindex="-1" hidden></p>
        <p class="signup">アカウントをお持ちでないですか? <a href="#demo-signup">新規登録の見本</a></p>
        <aside class="demo-note"><h2>この見本について</h2><p>架空のサービスの表示見本です。入力はこのページ内の確認だけに使い、外部送信・認証・登録・永続保存は行いません。配布HTMLはCC0・利用料¥0です。</p><p>初期画面ではダイアログを開きます。閉じるボタン・Escapeで閉じ、元のボタンから開き直せます。</p><p id="demo-reset" tabindex="-1"><b>パスワードの再設定</b> — リンク位置の表示見本です。再設定メールは送信しません。</p><p id="demo-signup" tabindex="-1"><b>新規登録</b> — リンク位置の表示見本です。アカウントの作成・画面遷移・課金は行いません。</p><p>外部認証の記号は文字で示しています。認証サービスのロゴ素材は含みません。</p><noscript><p>JavaScriptが無効なため開閉・入力確認・外部認証のボタンは動きません。リンクと入力欄の表示は確認できます。</p></noscript></aside>
      </dialog>
    </main>
    <script>

const form=document.querySelector('form'),status=document.querySelector('[data-demo-status]'),submit=document.querySelector('[data-demo-submit]');let composing=false;
function clearResult(){status.hidden=true;status.textContent='';form.querySelectorAll('[aria-invalid]').forEach(el=>el.removeAttribute('aria-invalid'));form.querySelectorAll('input').forEach(el=>el.setCustomValidity(''))}
function resetDemo(){form.reset();clearResult();composing=false;if(typeof updateMeter==='function')updateMeter()}
function validate(){if(composing)return;clearResult();const nickname=form.querySelector('[autocomplete="nickname"]'),password=form.querySelector('[data-new-password]');
if(nickname&&!nickname.value.trim())nickname.setCustomValidity('ニックネームを入力してください。');
if(password&&Array.from(password.value).length<8)password.setCustomValidity('この見本では8文字以上で入力してください。');
const invalid=[...form.querySelectorAll('input')].find(el=>!el.checkValidity());status.hidden=false;
if(invalid){invalid.setAttribute('aria-invalid','true');status.textContent='入力条件を確認してください。必須項目・形式・同意の状態を確認する見本です。';invalid.focus();invalid.reportValidity();return}
resetDemo();status.hidden=false;status.textContent='入力条件を確認しました。認証・登録・送信・保存は行っていません。';status.focus();}
form.addEventListener('submit',event=>event.preventDefault());form.addEventListener('compositionstart',()=>composing=true);form.addEventListener('compositionend',()=>composing=false);
form.addEventListener('keydown',event=>{if(event.key==='Enter'&&event.target.matches('input:not([type="checkbox"])')){if(event.isComposing||composing||event.keyCode===229)return;event.preventDefault();validate()}});
form.addEventListener('input',clearResult);form.addEventListener('change',clearResult);submit.addEventListener('click',validate);submit.disabled=false;
document.querySelectorAll('[data-demo-provider]').forEach(button=>{button.disabled=false;button.addEventListener('click',()=>{status.hidden=false;status.textContent=button.dataset.demoProvider+'との接続位置を示す見本です。外部認証・アカウント連携は行いません。';status.focus()})});

const dialog=document.querySelector('dialog'),launcher=document.querySelector('[data-demo-open]'),close=document.querySelector('[data-demo-close]');
function openDemo(){if(!dialog.open){dialog.showModal();dialog.scrollTop=0;document.getElementById('email').focus()}}
launcher.hidden=false;close.hidden=false;launcher.addEventListener('click',openDemo);close.addEventListener('click',()=>dialog.close());
dialog.addEventListener('close',()=>{resetDemo();launcher.focus()});
// 静的なopenを取り除き、同じ描画の初期化でネイティブのモーダルにする。
dialog.removeAttribute('open');openDemo();
    </script>
  </body>
</html>

2026年10月14日、Chromiumで320・390・768・1280pxの描画とキーボードのフォーカス表示を確認しました。他のブラウザは未確認です。利用先のブラウザと実データでも確認してください。

概要

グラスモーフィズムは、すりガラス越しに背景が透けるあの質感をUIに持ち込んだスタイルです。2013年の iOS 7、そして2020年の macOS Big Sur が「frosted glass(曇りガラス)」を全面採用したことで一般化しました。背景を完全に隠さず、ぼかしながら透かす——ログインモーダルにとって、この性質は単なる流行以上の意味を持ちます。

見本で試せる範囲

配布HTMLは、ブラウザー標準の dialog を使った入力デモです。閉じるボタンとEscapeで閉じ、元のボタンへフォーカスを戻して開き直せます。高さの足りない画面ではパネル内をスクロールします。メール形式と必須項目を確認すると入力を消し、認証・送信・保存を行っていないことを表示します。外部認証は説明だけを返し、ボタンにはロゴの代わりに略字を置いています。パスワード再設定と新規登録のリンクも、見本の説明へ移動します。

JavaScriptなしでは開いたパネルと説明を表示し、確認・外部認証の操作を無効にします。実サービスへの接続は含まないため、架空の値で表示と操作を確認してください。

文脈を保ったまま認証させる

ログインモーダルが背景を真っ黒な不透明レイヤーで覆うと、ユーザーは一瞬「どこに来たのか」を見失います。グラスモーフィズムのパネルは、背後のヒーロービジュアルやプロダクト画面を透かして残す。ユーザーはさっきまで見ていた世界の延長で認証しているという連続性を保てます。これは離脱率に直結する——文脈が途切れないことが、認証という面倒な作業のストレスを和らげるのです。

崩れる形真っ黒な不透明レイヤーで覆う

背後が完全に消えるため、利用者は一瞬どこに来たのかを見失います。認証が「別の場所へ連れて行かれた作業」になり、離脱の理由になります。

効く形ぼかしながら透かす

背後のヒーローやプロダクト画面が残るぶん、文脈が途切れません。影ではなくぼかしと透過で階層を作るので、身構えさせずに済みます。

ぼかしで作る、刺さない階層

通常、UIの奥行きは影(drop shadow)で表現します。影はコントラストが強く、ときに画面を「刺々しく」見せる。グラスモーフィズムは、ぼかし(backdrop-filter: blur)と透過と微光で奥行きを作る。同じ階層表現でも、後者ははるかに柔らかく、認証フローのような「身構えさせたくない」場面に適しています。

仕上げの判断軸

最大の弱点はコントラストです。すりガラスパネルの上にテキストを置くと、背景の明暗によって可読性が崩れる。

パネルに十分な不透明度の下地を敷き、入力欄とラベルのコントラスト比は必ず実測してください。すりガラスは背景の明暗で可読性が崩れます。

backdrop-filter は非対応ブラウザがあるため、半透明の単色塗りをフォールバックとして用意します。SSOボタンは3つまでに絞り、選択肢過多で迷わせないことも重要です。

認証の構成要素

認証の構成要素 メールアドレス パスワード 入力欄は最小限に 登録の項目が1つ増えるごとに、 完了する人は確実に減る autocomplete を書く username / current-password / new-password を使い分ける パスワード表示の切り替えを置く 「ログインできない」の多くは打ち間違い。見せる手段があるだけで解決する
認証画面は装飾より、入力の負担を減らすことが効きます。autocomplete を正しく書けば、多くの人は1タップで終わります。

使いどころ

  • SaaSプロダクトのログイン画面
  • エンタープライズSSO中心の認証
  • モダンなSpA・モバイルアプリのサインイン
  • 招待リンクからの参加フロー

このデザインの分類

カテゴリ
認証
スタイル
グラスモーフィズム / ダーク / クール / ミニマル

背景と狙いどころ

よくある質問

ガラス効果は古臭く見えませんか?
2020年前後の流行から定着した表現で、現在は「上品な視覚的階層を作る道具」として残っています。彩度を抑えれば古臭くなりません。
backdrop-filter のブラウザサポートは?
Chromium・Safari・Firefox いずれも標準サポート。古い Firefox(< 103)にはフォールバック(半透明の単色背景)を CSS で用意してください。
アクセシビリティに問題はないですか?
入力フィールドのコントラストが足りなくなりがち。背景のぼかしを強めてフォアグラウンド要素を浮き上がらせ、AA以上のコントラストを必ず計測してください。

この画面を実装する

動くサンプルとコピペできるコードを、技術別にまとめています。