登录页静态布局
• 完成登录页面的静态布局,不接入接口逻辑 • 掌握大背景图 + 登录卡片这种经典后台登录页结构 • 理解 CSS 背景图铺满方案:cover / contain / 固定尺寸 • 学会用绝对定位 + transform 实现登录卡片垂直居中 • 熟悉 Ant Design 5 的 Form、Input、Button 基础用法 • 了解 Less 嵌套语法与 box-sizing 在项目中的实际作用
新建 global.less
- styles/global.less
less
/* ============================== 全局样式 ============================== */
/* 统一全局盒模型为 border-box:元素宽高 = content + padding + border,避免布局计算异常 */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body,
#root {
width: 100%;
height: 100%;
}
body {
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
-webkit-font-smoothing: antialiased;
}main.tsx 引入全局global.less
ts
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './styles/global.less';
createRoot(document.getElementById('root')!).render(<App />);login页面的index.less
- 新建 styles/login/index.less
less
/* ============================== 登录页样式 ============================== */
// 背景图地址(内网部署时可替换为本地静态资源)
@login-bg-url: "https://jsopy.oss-cn-beijing.aliyuncs.com/IMAGES/banner/0.jpg";
.login-page {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
/* ---------- CSS 背景图铺满页面的三种核心方案 ----------
* 方案一:cover(生产环境采用)
* 等比缩放至完全覆盖容器,可能裁剪部分图像,但无拉伸、无留白、无失真,
* 适配任意屏幕尺寸。
*
* 方案二:contain(验证用,未采用)
* background-size: contain;
* 等比缩放至完整显示整张图,屏幕比例与图片不一致时两侧/上下会留白。
*
* 方案三:固定尺寸(验证用,未采用)
* background-size: 1920px 1080px;
* 背景图按固定像素铺放,屏幕大于该尺寸时背景无法铺满,会出现空白区域。
* ------------------------------------------------------ */
background-image: url(@login-bg-url);
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
// 背景遮罩层:提升卡片可读性
.login-mask {
position: absolute;
inset: 0;
background: linear-gradient(
135deg,
rgba(8, 18, 38, 0.55) 0%,
rgba(8, 18, 38, 0.25) 50%,
rgba(8, 18, 38, 0.55) 100%
);
}
// 登录卡片:绝对定位 + transform 垂直水平居中
.login-card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); // 兼容主流桌面端浏览器的居中方案
width: 400px;
max-width: calc(100vw - 48px); // 小屏幕下不溢出
padding: 40px 40px 32px;
background: rgba(255, 255, 255, 0.96);
border-radius: 12px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
backdrop-filter: blur(6px);
.login-header {
margin-bottom: 32px;
text-align: center;
.login-title {
margin-bottom: 8px;
font-size: 24px;
font-weight: 600;
color: #1f2d3d;
letter-spacing: 2px;
}
.login-subtitle {
font-size: 14px;
color: #8a97a8;
}
}
.login-form {
.login-submit-btn {
height: 44px;
font-size: 16px;
letter-spacing: 4px;
}
}
}
}login页面布局
tsx
import { Button, Form, Input } from "antd";
import { LockOutlined, UserOutlined } from "@ant-design/icons";
import "@/styles/login/index.less";
/** 登录表单数据类型 */
interface LoginFormValues {
username: string;
password: string;
}
function LoginPage() {
// 控制表单用的。可以获取表单的内容和校验结果
const [form] = Form.useForm<LoginFormValues>();
/** 提交登录(当前仅做前端校验,不接入后端接口) */
const handleSubmit = (values: LoginFormValues) => {
// console.log('登录表单校验通过:', values);
//写几个form 方法
form.validateFields().then(() => {
console.log("登录表单校验通过77777:", values);
// 获取单个字段值
// const username = form.getFieldValue("username");
// console.log("username:", username);
// 表单赋值
// form.setFieldsValue({
// username: "admin",
// password: "123456",
// });
//重置表单
// form.resetFields();
});
};
return (
<div className="login-page">
<div className="login-mask" />
<div className="login-card">
<div className="login-header">
<h1 className="login-title">后台管理系统</h1>
<p className="login-subtitle">欢迎登录,请使用您的账号</p>
</div>
<Form<LoginFormValues>
form={form}
className="login-form"
size="large"
onFinish={handleSubmit}
>
<Form.Item
name="username"
rules={[
{ required: true, message: "请输入用户名" },
{ min: 3, max: 20, message: "用户名长度需在 3-20 个字符之间" },
]}
>
<Input prefix={<UserOutlined />} placeholder="用户名" allowClear />
</Form.Item>
<Form.Item
name="password"
rules={[
{ required: true, message: "请输入密码" },
{ min: 6, max: 20, message: "密码长度需在 6-20 个字符之间" },
]}
>
<Input.Password prefix={<LockOutlined />} placeholder="密码" />
</Form.Item>
<Form.Item>
<Button
type="primary"
htmlType="submit"
block
className="login-submit-btn"
>
登 录
</Button>
</Form.Item>
</Form>
</div>
</div>
);
}
export default LoginPage;