设计思路
- 布局: 采用经典的居中卡片式布局,将登录表单放置在一个独立的卡片容器中,视觉上更聚焦、更专业。
- 色彩: 使用一个主色调(代表信任和科技的蓝色),并搭配柔和的灰色作为辅助色,营造简洁、清爽的氛围。
- 字体: 选择一款清晰易读的无衬线字体,如
Helvetica Neue,Arial,PingFang SC(Mac),Microsoft YaHei(Win) 等,确保跨平台的一致性。 - 交互与动画:
- 输入框获得焦点时,边框颜色平滑过渡到主色调。
- 添加一个微妙的加载动画(登录按钮上的旋转图标),提升用户体验。
- 使用
placeholder-shown伪类,让标签文字在输入时优雅地浮动到上方。
- 响应式: 确保页面在不同尺寸的设备(桌面、平板、手机)上都能良好显示。
- 图标: 使用 Font Awesome 图标库,让界面元素更直观。
最终效果预览
-
桌面端:
(图片来源网络,侵删) -
移动端:
完整代码
您可以直接将以下代码复制到一个 .html 文件中,然后在浏览器中打开查看效果。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">邮箱登录 - MailBox</title>
<!-- 引入 Font Awesome 图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* --- 全局样式和变量 --- */
:root {
--primary-color: #4a6cf7; /* 主色调,蓝色 */
--secondary-color: #f0f2f5; /* 背景色,浅灰 */
--text-color: #333; /* 主要文字颜色 */
--light-text: #666; /* 次要文字颜色 */
--border-color: #ddd; /* 边框颜色 */
--error-color: #e74c3c; /* 错误提示颜色 */
--shadow: 0 4px 12px rgba(0, 0, 0, 0.1); /* 卡片阴影 */
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: var(--secondary-color);
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect width="100" height="100" fill="%23f0f2f5"/><path d="M11 0 L22 11 L11 22 Z" fill="%23e0e2e5"/></svg>');
background-size: 200px 200px;
}
/* --- 登录卡片容器 --- */
.login-card {
background-color: #fff;
padding: 40px;
border-radius: 12px;
box-shadow: var(--shadow);
width: 100%;
max-width: 420px;
transition: transform 0.3s ease;
}
.login-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
/* --- Logo 和标题 --- */
.login-header {
text-align: center;
margin-bottom: 30px;
}
.logo {
font-size: 48px;
color: var(--primary-color);
margin-bottom: 10px;
}
.login-title {
font-size: 24px;
font-weight: 600;
color: var(--text-color);
}
.login-subtitle {
font-size: 14px;
color: var(--light-text);
margin-top: 5px;
}
/* --- 表单样式 --- */
.form-group {
position: relative;
margin-bottom: 25px;
}
.form-input {
width: 100%;
padding: 12px 15px 12px 45px;
font-size: 16px;
border: 1px solid var(--border-color);
border-radius: 8px;
outline: none;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
background-color: #fafafa;
}
.form-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(74, 108, 247, 0.1);
background-color: #fff;
}
/* 输入框前的图标 */
.input-icon {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: var(--light-text);
}
/* 标签浮动效果 */
.form-label {
position: absolute;
left: 45px;
top: 50%;
transform: translateY(-50%);
background-color: #fafafa;
padding: 0 5px;
color: var(--light-text);
transition: all 0.3s ease;
pointer-events: none;
}
.form-input:focus ~ .form-label,
.form-input:not(:placeholder-shown) ~ .form-label {
top: 0;
font-size: 12px;
color: var(--primary-color);
}
/* 记住我和忘记密码 --- */
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
font-size: 14px;
}
.remember-me {
display: flex;
align-items: center;
}
.remember-me input[type="checkbox"] {
margin-right: 6px;
cursor: pointer;
}
.remember-me label {
cursor: pointer;
user-select: none;
}
.forgot-password {
color: var(--primary-color);
text-decoration: none;
transition: opacity 0.3s ease;
}
.forgot-password:hover {
opacity: 0.8;
}
/* --- 登录按钮 --- */
.login-button {
width: 100%;
padding: 14px;
font-size: 16px;
font-weight: 600;
color: #fff;
background-color: var(--primary-color);
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
position: relative;
overflow: hidden;
}
.login-button:hover {
background-color: #3a5ce5;
}
.login-button:active {
transform: scale(0.98);
}
/* 加载动画 */
.spinner {
display: none;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
}
.login-button.loading .spinner {
display: block;
}
.login-button.loading .button-text {
visibility: hidden;
}
@keyframes spin {
to { transform: translateY(-50%) rotate(360deg); }
}
/* --- 错误提示 --- */
.error-message {
color: var(--error-color);
font-size: 14px;
margin-top: 5px;
display: none;
}
.form-group.has-error .form-input {
border-color: var(--error-color);
}
.form-group.has-error .error-message {
display: block;
}
/* --- 其他登录方式 --- */
.divider {
text-align: center;
margin: 30px 0;
position: relative;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background-color: var(--border-color);
}
.divider span {
background-color: #fff;
padding: 0 15px;
color: var(--light-text);
font-size: 14px;
}
.social-login {
display: flex;
justify-content: center;
gap: 15px;
}
.social-button {
width: 50px;
height: 50px;
border-radius: 50%;
border: 1px solid var(--border-color);
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.3s ease;
font-size: 20px;
}
.social-button:hover {
border-color: var(--primary-color);
color: var(--primary-color);
transform: translateY(-3px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
/* --- 响应式设计 --- */
@media (max-width: 480px) {
.login-card {
padding: 30px 20px;
}
.login-title {
font-size: 22px;
}
}
</style>
</head>
<body>
<main class="login-card">
<header class="login-header">
<div class="logo">
<i class="fas fa-envelope"></i>
</div>
<h1 class="login-title">欢迎回来</h1>
<p class="login-subtitle">请登录您的邮箱账户</p>
</header>
<form id="loginForm" class="login-form">
<div class="form-group">
<i class="fas fa-user input-icon"></i>
<input
type="email"
id="email"
class="form-input"
placeholder=" "
required
>
<label for="email" class="form-label">邮箱地址</label>
<div class="error-message">请输入有效的邮箱地址</div>
</div>
<div class="form-group">
<i class="fas fa-lock input-icon"></i>
<input
type="password"
id="password"
class="form-input"
placeholder=" "
required
>
<label for="password" class="form-label">密码</label>
<div class="error-message">密码不能为空</div>
</div>
<div class="form-options">
<div class="remember-me">
<input type="checkbox" id="remember">
<label for="remember">记住我</label>
</div>
<a href="#" class="forgot-password">忘记密码?</a>
</div>
<button type="submit" class="login-button">
<span class="button-text">登录</span>
<div class="spinner"></div>
</button>
</form>
<div class="divider">
<span>或使用以下方式登录</span>
</div>
<div class="social-login">
<button class="social-button" title="使用 Google 登录">
<i class="fab fa-google"></i>
</button>
<button class="social-button" title="使用 GitHub 登录">
<i class="fab fa-github"></i>
</button>
<button class="social-button" title="使用 微信 登录">
<i class="fab fa-weixin"></i>
</button>
</div>
</main>
<script>
document.addEventListener('DOMContentLoaded', function () {
const loginForm = document.getElementById('loginForm');
const loginButton = document.querySelector('.login-button');
loginForm.addEventListener('submit', function (event) {
event.preventDefault(); // 阻止表单默认提交行为
// 获取输入框和错误信息元素
const emailInput = document.getElementById('email');
const passwordInput = document.getElementById('password');
const emailGroup = emailInput.closest('.form-group');
const passwordGroup = passwordInput.closest('.form-group');
// 重置错误状态
emailGroup.classList.remove('has-error');
passwordGroup.classList.remove('has-error');
let isValid = true;
// 简单的邮箱格式验证
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(emailInput.value)) {
emailGroup.classList.add('has-error');
isValid = false;
}
// 密码非空验证
if (passwordInput.value.trim() === '') {
passwordGroup.classList.add('has-error');
isValid = false;
}
// 如果验证通过,则显示加载状态并模拟登录
if (isValid) {
loginButton.classList.add('loading');
// 模拟网络请求
setTimeout(() => {
loginButton.classList.remove('loading');
alert('登录成功!\n(这是一个演示,实际应用中会跳转到邮箱主页)');
// window.location.href = 'inbox.html'; // 实际应用中的跳转
}, 1500);
}
});
// 社交登录按钮点击事件
document.querySelectorAll('.social-button').forEach(button => {
button.addEventListener('click', function() {
const provider = this.getAttribute('title');
alert(`正在使用 ${provider} 登录...`);
});
});
});
</script>
</body>
</html>
代码解析
HTML 结构
- 语义化标签: 使用
<main>,<header>,<form>等语义化标签,使页面结构清晰,对搜索引擎和屏幕阅读器更友好。 <form>: 包含所有登录相关的输入控件。.form-group: 将输入框、图标和标签包裹在一起,方便进行样式控制和状态管理(如错误状态)。.divider和.social-login: 提供了其他登录方式的视觉分隔和按钮。
CSS 样式
- CSS 变量 (
root): 将颜色、阴影等常用值定义为变量,方便全局统一修改和维护。 - 卡片式布局:
.login-card通过margin: auto和max-width实现水平居中,并添加了圆角和阴影,使其从背景中凸显出来。 - 浮动标签: 这是现代表单设计的一个亮点,通过
.form-input:focus ~ .form-label和.form-input:not(:placeholder-shown) ~ .form-label选择器,巧妙地实现了当输入框获得焦点或有内容时,标签文字平滑地“浮动”到输入框上方的效果。 - 交互反馈:
hover和focus伪类为按钮和输入框提供了清晰的视觉反馈。transform: translateY(-5px)在鼠标悬停时让卡片轻微上浮,增强了交互感。
- 加载动画: 使用 CSS
@keyframes创建了一个简单的旋转加载图标,通过添加/移除.loading类来控制其显示。
JavaScript 交互
- 表单验证: 在
submit事件中,阻止了默认提交行为,然后使用正则表达式对邮箱格式进行验证,对密码进行非空验证。 - 错误状态管理: 如果验证失败,会为对应的
.form-group添加has-error类,该类会改变输入框的边框颜色并显示错误信息。 - 模拟登录: 验证通过后,为登录按钮添加
loading类,显示加载动画。setTimeout模拟了一个 1.5 秒的网络请求,请求完成后移除加载状态并弹出提示。 - 社交登录: 为社交按钮添加了点击事件,方便后续扩展功能。
这个设计不仅美观,而且功能完整、交互友好,可以作为现代 Web 应用的一个优秀登录页面模板。

(图片来源网络,侵删)
