1
This commit is contained in:
312
docs/LESS使用指南.md
Normal file
312
docs/LESS使用指南.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# LESS 使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
本项目已全面从 CSS 转换为 LESS,使用 LESS 的嵌套结构、变量、混合等特性来提高代码的可维护性和复用性。
|
||||
|
||||
## 🎯 LESS 的优势
|
||||
|
||||
### 1. **嵌套结构**
|
||||
- 更清晰的代码层次结构
|
||||
- 减少选择器重复
|
||||
- 提高代码可读性
|
||||
|
||||
### 2. **变量系统**
|
||||
- 统一的颜色、字体、间距管理
|
||||
- 快速修改全局样式
|
||||
- 减少重复值
|
||||
|
||||
### 3. **混合(Mixins)**
|
||||
- 可复用的样式块
|
||||
- 参数化样式
|
||||
- 减少代码重复
|
||||
|
||||
### 4. **函数和运算**
|
||||
- 动态计算尺寸
|
||||
- 颜色混合和透明度
|
||||
- 响应式断点管理
|
||||
|
||||
## 📁 文件结构
|
||||
|
||||
```
|
||||
src/assets/css/
|
||||
├── variables.less # 全局变量定义
|
||||
├── common.less # 通用样式
|
||||
├── animations.less # 动画效果
|
||||
├── mobile_responsive.less # 移动端响应式
|
||||
└── common_mobile.less # 通用移动端适配
|
||||
```
|
||||
|
||||
## 🔧 已配置的 LESS 功能
|
||||
|
||||
### 1. **全局变量**
|
||||
- 颜色系统(主色、成功、警告、错误等)
|
||||
- 字体系统(大小、行高、字重)
|
||||
- 间距系统(内边距、外边距)
|
||||
- 断点系统(移动端、平板、桌面)
|
||||
- 动画系统(时长、缓动、延迟)
|
||||
|
||||
### 2. **响应式混合**
|
||||
```less
|
||||
.mobile({
|
||||
// 移动端样式
|
||||
});
|
||||
|
||||
.tablet({
|
||||
// 平板端样式
|
||||
});
|
||||
|
||||
.desktop({
|
||||
// 桌面端样式
|
||||
});
|
||||
```
|
||||
|
||||
### 3. **设备检测混合**
|
||||
```less
|
||||
.touch-device({
|
||||
// 触摸设备样式
|
||||
});
|
||||
|
||||
.high-dpi({
|
||||
// 高分辨率屏幕样式
|
||||
});
|
||||
|
||||
.landscape({
|
||||
// 横屏模式样式
|
||||
});
|
||||
```
|
||||
|
||||
## 📝 使用方法
|
||||
|
||||
### 1. **引入变量文件**
|
||||
```less
|
||||
@import './variables.less';
|
||||
```
|
||||
|
||||
### 2. **使用变量**
|
||||
```less
|
||||
.button {
|
||||
background-color: @primary-color;
|
||||
padding: @padding-md;
|
||||
border-radius: @border-radius-base;
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. **嵌套结构**
|
||||
```less
|
||||
.card {
|
||||
padding: @card-padding-base;
|
||||
border: @border-width-base solid @border-color;
|
||||
|
||||
.card-header {
|
||||
padding: @padding-md;
|
||||
border-bottom: @border-width-base solid @border-color-light;
|
||||
|
||||
.card-title {
|
||||
font-size: @font-size-h4;
|
||||
color: @heading-color;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: @padding-md;
|
||||
|
||||
.card-text {
|
||||
color: @text-color;
|
||||
line-height: @line-height-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. **使用混合**
|
||||
```less
|
||||
.responsive-button {
|
||||
.mobile({
|
||||
width: 100%;
|
||||
padding: @padding-sm;
|
||||
font-size: @font-size-sm;
|
||||
});
|
||||
|
||||
.tablet({
|
||||
width: auto;
|
||||
padding: @padding-md;
|
||||
font-size: @font-size-base;
|
||||
});
|
||||
|
||||
.desktop({
|
||||
padding: @padding-lg;
|
||||
font-size: @font-size-lg;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 5. **颜色操作**
|
||||
```less
|
||||
.button {
|
||||
background-color: @primary-color;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten(@primary-color, 10%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: darken(@primary-color, 10%);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background-color: fade(@primary-color, 50%);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎨 颜色系统
|
||||
|
||||
### 主色调
|
||||
- `@primary-color`: #3498db
|
||||
- `@primary-light`: #5dade2
|
||||
- `@primary-dark`: #2980b9
|
||||
- `@primary-lighter`: #ebf3fd
|
||||
|
||||
### 功能色
|
||||
- `@success-color`: #52c41a
|
||||
- `@warning-color`: #faad14
|
||||
- `@error-color`: #f5222d
|
||||
- `@info-color`: #1890ff
|
||||
|
||||
### 中性色
|
||||
- `@white`: #ffffff
|
||||
- `@black`: #000000
|
||||
- `@gray-1` 到 `@gray-10`: 从浅到深的灰色
|
||||
|
||||
## 📱 响应式断点
|
||||
|
||||
### 断点变量
|
||||
- `@screen-xs`: 480px
|
||||
- `@screen-sm`: 576px
|
||||
- `@screen-md`: 768px
|
||||
- `@screen-lg`: 992px
|
||||
- `@screen-xl`: 1200px
|
||||
- `@screen-xxl`: 1600px
|
||||
|
||||
### 设备断点
|
||||
- `@mobile-breakpoint`: 768px
|
||||
- `@tablet-breakpoint`: 992px
|
||||
- `@desktop-breakpoint`: 1200px
|
||||
|
||||
## 🔄 动画系统
|
||||
|
||||
### 动画时长
|
||||
- `@animation-duration-base`: 0.2s
|
||||
- `@animation-duration-fast`: 0.1s
|
||||
- `@animation-duration-slow`: 0.3s
|
||||
- `@animation-duration-slower`: 0.5s
|
||||
|
||||
### 动画缓动
|
||||
- `@animation-timing-base`: ease
|
||||
- `@animation-timing-ease-in`: ease-in
|
||||
- `@animation-timing-ease-out`: ease-out
|
||||
- `@animation-timing-ease-in-out`: ease-in-out
|
||||
- `@animation-timing-linear`: linear
|
||||
|
||||
## 🛠️ 开发工具
|
||||
|
||||
### 1. **Vue CLI 配置**
|
||||
项目已配置 LESS 支持,包括:
|
||||
- LESS 编译器
|
||||
- 全局变量注入
|
||||
- 自动前缀处理
|
||||
|
||||
### 2. **构建命令**
|
||||
```bash
|
||||
# 开发模式
|
||||
yarn serve
|
||||
|
||||
# 生产构建
|
||||
yarn build
|
||||
```
|
||||
|
||||
## 📋 最佳实践
|
||||
|
||||
### 1. **变量命名**
|
||||
- 使用语义化名称
|
||||
- 遵循 BEM 命名规范
|
||||
- 保持命名一致性
|
||||
|
||||
### 2. **嵌套深度**
|
||||
- 避免超过 3 层嵌套
|
||||
- 使用 `&` 符号引用父选择器
|
||||
- 保持选择器简洁
|
||||
|
||||
### 3. **混合使用**
|
||||
- 创建可复用的混合
|
||||
- 参数化常用样式
|
||||
- 避免过度抽象
|
||||
|
||||
### 4. **文件组织**
|
||||
- 按功能模块组织文件
|
||||
- 使用 `@import` 引入依赖
|
||||
- 保持文件结构清晰
|
||||
|
||||
## 🚀 性能优化
|
||||
|
||||
### 1. **变量缓存**
|
||||
- 减少重复计算
|
||||
- 使用预定义值
|
||||
- 避免运行时计算
|
||||
|
||||
### 2. **选择器优化**
|
||||
- 避免过深嵌套
|
||||
- 使用类选择器
|
||||
- 减少选择器复杂度
|
||||
|
||||
### 3. **媒体查询优化**
|
||||
- 使用混合管理断点
|
||||
- 避免重复的媒体查询
|
||||
- 合并相似的样式规则
|
||||
|
||||
## 🔍 调试技巧
|
||||
|
||||
### 1. **浏览器开发工具**
|
||||
- 查看编译后的 CSS
|
||||
- 检查选择器优先级
|
||||
- 调试响应式样式
|
||||
|
||||
### 2. **LESS 编译错误**
|
||||
- 检查语法错误
|
||||
- 验证变量引用
|
||||
- 确认文件路径
|
||||
|
||||
### 3. **样式冲突**
|
||||
- 使用 `!important` 谨慎
|
||||
- 检查选择器特异性
|
||||
- 验证样式继承
|
||||
|
||||
## 📚 学习资源
|
||||
|
||||
### 1. **官方文档**
|
||||
- [LESS 官网](http://lesscss.org/)
|
||||
- [LESS 语言特性](http://lesscss.org/features/)
|
||||
- [LESS 函数参考](http://lesscss.org/functions/)
|
||||
|
||||
### 2. **在线工具**
|
||||
- [LESS 在线编译器](http://lesscss.org/less-preview/)
|
||||
- [LESS 语法检查器](https://github.com/less/less.js)
|
||||
|
||||
### 3. **社区资源**
|
||||
- [LESS GitHub](https://github.com/less/less.js)
|
||||
- [LESS 论坛](https://github.com/less/less.js/discussions)
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
通过使用 LESS,我们实现了:
|
||||
|
||||
1. **更好的代码组织**:嵌套结构和模块化文件
|
||||
2. **统一的样式管理**:全局变量和混合系统
|
||||
3. **高效的开发流程**:快速修改和样式复用
|
||||
4. **响应式设计**:断点管理和设备适配
|
||||
5. **维护性提升**:清晰的代码结构和语义化命名
|
||||
|
||||
LESS 为项目提供了强大的样式管理能力,让开发更加高效,维护更加简单。
|
||||
314
docs/动画效果使用指南.md
Normal file
314
docs/动画效果使用指南.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# 动画效果使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
本项目已集成丰富的动画效果库,包含多种CSS动画、悬停效果、滚动触发动画等,让页面更加生动有趣。
|
||||
|
||||
## 🎯 已集成的动画类型
|
||||
|
||||
### 1. 基础动画类
|
||||
|
||||
#### 淡入动画
|
||||
- `.fade-in` - 淡入
|
||||
- `.fade-in-up` - 从下方淡入
|
||||
- `.fade-in-down` - 从上方淡入
|
||||
- `.fade-in-left` - 从左侧淡入
|
||||
- `.fade-in-right` - 从右侧淡入
|
||||
|
||||
#### 滑入动画
|
||||
- `.slide-in-up` - 从下方滑入
|
||||
- `.slide-in-down` - 从上方滑入
|
||||
- `.slide-in-left` - 从左侧滑入
|
||||
- `.slide-in-right` - 从右侧滑入
|
||||
|
||||
#### 缩放动画
|
||||
- `.zoom-in` - 缩放进入
|
||||
- `.zoom-out` - 缩放退出
|
||||
|
||||
#### 特殊效果动画
|
||||
- `.bounce` - 弹跳
|
||||
- `.pulse` - 脉冲
|
||||
- `.shake` - 抖动
|
||||
- `.swing` - 摇摆
|
||||
- `.rotate-in` - 旋转进入
|
||||
- `.flip-in-x` - X轴翻转
|
||||
- `.flip-in-y` - Y轴翻转
|
||||
- `.light-speed-in` - 光速进入
|
||||
- `.rubber-band` - 橡皮筋
|
||||
- `.wobble` - 摇摆
|
||||
- `.tada` - 庆祝
|
||||
- `.heart-beat` - 心跳
|
||||
- `.hinge` - 铰链
|
||||
- `.roll-in` - 滚入
|
||||
- `.roll-out` - 滚出
|
||||
|
||||
### 2. 悬停动画效果
|
||||
|
||||
- `.hover-lift` - 悬停时上浮
|
||||
- `.hover-scale` - 悬停时缩放
|
||||
- `.hover-rotate` - 悬停时旋转
|
||||
- `.hover-glow` - 悬停时发光
|
||||
- `.hover-bounce` - 悬停时弹跳
|
||||
|
||||
### 3. 滚动触发动画
|
||||
|
||||
- `.animate-on-scroll` - 滚动时触发动画
|
||||
- `.animate-stagger` - 交错动画容器
|
||||
|
||||
### 4. 高级动画效果
|
||||
|
||||
- `.gradient-bg` - 渐变背景动画
|
||||
- `.neon-text` - 霓虹灯文字效果
|
||||
- `.wave` - 波浪效果
|
||||
- `.particles` - 粒子效果
|
||||
- `.flip-card` - 3D翻转卡片
|
||||
- `.typewriter` - 打字机效果
|
||||
|
||||
## 🚀 使用方法
|
||||
|
||||
### 基础用法
|
||||
|
||||
```html
|
||||
<!-- 添加动画类 -->
|
||||
<div class="animate fade-in-up">这个元素会从下方淡入</div>
|
||||
|
||||
<!-- 设置动画时长 -->
|
||||
<div class="animate fast fade-in-up">快速动画</div>
|
||||
<div class="animate slow fade-in-up">慢速动画</div>
|
||||
|
||||
<!-- 设置动画延迟 -->
|
||||
<div class="animate fade-in-up delay-1s">延迟1秒</div>
|
||||
<div class="animate fade-in-up delay-2s">延迟2秒</div>
|
||||
|
||||
<!-- 无限循环 -->
|
||||
<div class="animate infinite pulse">无限脉冲</div>
|
||||
```
|
||||
|
||||
### 悬停效果
|
||||
|
||||
```html
|
||||
<!-- 悬停时上浮 -->
|
||||
<div class="hover-lift">悬停时会上浮</div>
|
||||
|
||||
<!-- 悬停时缩放 -->
|
||||
<div class="hover-scale">悬停时会缩放</div>
|
||||
|
||||
<!-- 悬停时发光 -->
|
||||
<div class="hover-glow">悬停时会发光</div>
|
||||
```
|
||||
|
||||
### 滚动触发动画
|
||||
|
||||
```html
|
||||
<!-- 滚动时触发 -->
|
||||
<div class="animate-on-scroll">滚动到此处时显示</div>
|
||||
|
||||
<!-- 交错动画 -->
|
||||
<div class="animate-stagger">
|
||||
<div>第一个元素</div>
|
||||
<div>第二个元素</div>
|
||||
<div>第三个元素</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 组合使用
|
||||
|
||||
```html
|
||||
<!-- 组合多个动画类 -->
|
||||
<div class="animate fade-in-up delay-1s hover-lift">
|
||||
延迟淡入 + 悬停上浮
|
||||
</div>
|
||||
|
||||
<!-- 动画容器 + 悬停效果 -->
|
||||
<div class="animate-stagger">
|
||||
<div class="hover-scale">悬停缩放</div>
|
||||
<div class="hover-glow">悬停发光</div>
|
||||
<div class="hover-rotate">悬停旋转</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## 🎨 自定义动画
|
||||
|
||||
### 创建新的关键帧动画
|
||||
|
||||
```css
|
||||
@keyframes customAnimation {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.custom-animate {
|
||||
animation-name: customAnimation;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
```
|
||||
|
||||
### 自定义悬停效果
|
||||
|
||||
```css
|
||||
.custom-hover {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-hover:hover {
|
||||
transform: translateY(-20px) rotate(10deg);
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 JavaScript 动画控制
|
||||
|
||||
### 使用动画助手
|
||||
|
||||
```javascript
|
||||
// 手动触发动画
|
||||
window.animationHelper.triggerAnimation(element, 'fade-in');
|
||||
|
||||
// 添加滚动动画
|
||||
window.animationHelper.addScrollAnimation(element, {
|
||||
threshold: 0.2,
|
||||
delay: 0.5
|
||||
});
|
||||
|
||||
// 添加交错动画
|
||||
window.animationHelper.addStaggerAnimation(container, {
|
||||
delay: 0.2,
|
||||
staggerDelay: 0.1
|
||||
});
|
||||
```
|
||||
|
||||
### 事件监听
|
||||
|
||||
```javascript
|
||||
// 监听动画开始事件
|
||||
element.addEventListener('animationStart', (event) => {
|
||||
console.log('动画开始:', event.detail);
|
||||
});
|
||||
|
||||
// 监听动画触发事件
|
||||
element.addEventListener('animationTrigger', (event) => {
|
||||
console.log('动画触发:', event.detail);
|
||||
});
|
||||
```
|
||||
|
||||
## 📱 响应式动画
|
||||
|
||||
### 移动端优化
|
||||
|
||||
```css
|
||||
/* 移动端减少动画复杂度 */
|
||||
@media (max-width: 768px) {
|
||||
.animate {
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.floating-particles {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 性能优化
|
||||
|
||||
```css
|
||||
/* 使用 will-change 优化性能 */
|
||||
.animate {
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
/* 使用 transform3d 启用硬件加速 */
|
||||
.animate {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
```
|
||||
|
||||
## 🎭 动画最佳实践
|
||||
|
||||
### 1. 适度使用
|
||||
- 不要过度使用动画,影响用户体验
|
||||
- 保持动画简洁明了
|
||||
- 考虑用户的动画偏好设置
|
||||
|
||||
### 2. 性能考虑
|
||||
- 使用 `transform` 和 `opacity` 属性
|
||||
- 避免在动画中改变布局属性
|
||||
- 合理使用 `will-change` 属性
|
||||
|
||||
### 3. 可访问性
|
||||
- 尊重用户的 `prefers-reduced-motion` 设置
|
||||
- 提供动画开关选项
|
||||
- 确保动画不影响内容可读性
|
||||
|
||||
### 4. 时机控制
|
||||
- 页面加载完成后延迟启动动画
|
||||
- 滚动触发动画使用 Intersection Observer
|
||||
- 合理设置动画延迟和持续时间
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q: 动画不工作?
|
||||
A: 检查是否正确引入了 `animations.css` 文件,确保元素有正确的类名。
|
||||
|
||||
### Q: 动画性能差?
|
||||
A: 使用 `transform` 和 `opacity` 属性,避免改变布局属性,启用硬件加速。
|
||||
|
||||
### Q: 移动端动画卡顿?
|
||||
A: 减少动画复杂度,使用更简单的动画效果,考虑禁用某些复杂动画。
|
||||
|
||||
### Q: 如何禁用动画?
|
||||
A: 在CSS中添加 `animation: none !important;` 或使用 `prefers-reduced-motion` 媒体查询。
|
||||
|
||||
## 📚 示例代码
|
||||
|
||||
### 完整的动画页面示例
|
||||
|
||||
```html
|
||||
<template>
|
||||
<div class="animated-page">
|
||||
<!-- 滚动进度条 -->
|
||||
<div class="scroll-progress-bar" data-scroll-progress="bar"></div>
|
||||
|
||||
<!-- 横幅区域 -->
|
||||
<div class="banner animate-on-scroll">
|
||||
<h1 class="animate fade-in-down text-glow">欢迎访问</h1>
|
||||
<p class="animate fade-in-up delay-1s">精彩内容即将呈现</p>
|
||||
</div>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<div class="content animate-stagger">
|
||||
<div class="card hover-lift">
|
||||
<div class="icon animate pulse infinite">🚀</div>
|
||||
<h3>快速开始</h3>
|
||||
<p>简单易用的开发体验</p>
|
||||
</div>
|
||||
|
||||
<div class="card hover-scale">
|
||||
<div class="icon animate bounce delay-1s">⚡</div>
|
||||
<h3>高性能</h3>
|
||||
<p>优化的性能表现</p>
|
||||
</div>
|
||||
|
||||
<div class="card hover-glow">
|
||||
<div class="icon animate wobble delay-2s">🎨</div>
|
||||
<h3>美观设计</h3>
|
||||
<p>现代化的视觉体验</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
通过合理使用这些动画效果,可以让您的页面更加生动有趣,提升用户体验。记住要适度使用,注重性能优化,并考虑可访问性需求。
|
||||
307
docs/移动端适配指南.md
Normal file
307
docs/移动端适配指南.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# 移动端适配指南
|
||||
|
||||
## 概述
|
||||
|
||||
本项目已全面适配移动端,包括响应式布局、触摸优化、性能优化等,确保在各种移动设备上都有良好的用户体验。
|
||||
|
||||
## 🎯 已实现的移动端适配
|
||||
|
||||
### 1. 响应式导航
|
||||
- **桌面端导航**:完整的主菜单和下拉菜单
|
||||
- **移动端导航**:汉堡菜单 + 全屏移动端菜单
|
||||
- **返回按钮**:移动端菜单中的返回功能,已修复显示问题
|
||||
|
||||
### 2. 响应式布局
|
||||
- **断点设置**:
|
||||
- 移动端:≤768px
|
||||
- 平板端:769px-1024px
|
||||
- 桌面端:>1024px
|
||||
- **网格系统**:自动从多列调整为单列
|
||||
- **容器适配**:边距和间距自动调整
|
||||
|
||||
### 3. 触摸设备优化
|
||||
- **触摸友好尺寸**:按钮最小高度44px
|
||||
- **触摸友好间距**:菜单项间距优化
|
||||
- **触摸反馈**:移动端禁用悬停效果
|
||||
|
||||
### 4. 性能优化
|
||||
- **移动端动画简化**:减少复杂动画
|
||||
- **图片优化**:高分辨率屏幕支持
|
||||
- **硬件加速**:启用GPU加速
|
||||
|
||||
## 📱 移动端适配详情
|
||||
|
||||
### 头部导航适配
|
||||
|
||||
#### 桌面端导航
|
||||
```html
|
||||
<div class="bottom desktop">
|
||||
<!-- 完整的主菜单 -->
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 移动端导航
|
||||
```html
|
||||
<div class="bottom headerBottom mobile">
|
||||
<!-- 移动端导航栏 -->
|
||||
</div>
|
||||
|
||||
<div id="mobileMenu" class="headerMobileMenu bread">
|
||||
<!-- 移动端全屏菜单 -->
|
||||
</div>
|
||||
```
|
||||
|
||||
#### 返回按钮修复
|
||||
```css
|
||||
/* 返回按钮移动端适配 */
|
||||
.goBack {
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 2px solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.linkGoBack {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.linkGoBack img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 10px;
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
```
|
||||
|
||||
### 页面布局适配
|
||||
|
||||
#### 横幅区域
|
||||
```css
|
||||
@media (max-width: 768px) {
|
||||
.page-banner {
|
||||
padding: 60px 0 40px !important;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 2.5rem !important;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1.2rem !important;
|
||||
line-height: 1.4 !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 网格布局
|
||||
```css
|
||||
@media (max-width: 768px) {
|
||||
.advantages-grid,
|
||||
.areas-grid,
|
||||
.services-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 20px !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 卡片组件
|
||||
```css
|
||||
@media (max-width: 768px) {
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card {
|
||||
padding: 25px 20px !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 使用方法
|
||||
|
||||
### 1. 自动适配
|
||||
大部分页面会自动适配移动端,无需额外配置。
|
||||
|
||||
### 2. 手动添加移动端类
|
||||
```html
|
||||
<!-- 移动端隐藏 -->
|
||||
<div class="desktop-only">仅桌面端显示</div>
|
||||
|
||||
<!-- 移动端显示 -->
|
||||
<div class="mobile-only">仅移动端显示</div>
|
||||
|
||||
<!-- 响应式容器 -->
|
||||
<div class="container">自动适配边距</div>
|
||||
|
||||
<!-- 响应式网格 -->
|
||||
<div class="grid">自动调整列数</div>
|
||||
```
|
||||
|
||||
### 3. 自定义断点
|
||||
```css
|
||||
/* 自定义移动端断点 */
|
||||
@media (max-width: 600px) {
|
||||
.custom-element {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📐 断点规范
|
||||
|
||||
### 标准断点
|
||||
```css
|
||||
/* 超小屏幕 */
|
||||
@media (max-width: 360px) { }
|
||||
|
||||
/* 小屏幕手机 */
|
||||
@media (max-width: 480px) { }
|
||||
|
||||
/* 移动端 */
|
||||
@media (max-width: 768px) { }
|
||||
|
||||
/* 平板端 */
|
||||
@media (min-width: 769px) and (max-width: 1024px) { }
|
||||
|
||||
/* 桌面端 */
|
||||
@media (min-width: 1025px) { }
|
||||
```
|
||||
|
||||
### 特殊断点
|
||||
```css
|
||||
/* 横屏模式 */
|
||||
@media (orientation: landscape) and (max-height: 500px) { }
|
||||
|
||||
/* 触摸设备 */
|
||||
@media (hover: none) and (pointer: coarse) { }
|
||||
|
||||
/* 高分辨率屏幕 */
|
||||
@media (-webkit-min-device-pixel-ratio: 2) { }
|
||||
|
||||
/* 深色模式 */
|
||||
@media (prefers-color-scheme: dark) { }
|
||||
|
||||
/* 减少动画偏好 */
|
||||
@media (prefers-reduced-motion: reduce) { }
|
||||
```
|
||||
|
||||
## 🎨 移动端样式规范
|
||||
|
||||
### 1. 字体大小
|
||||
- **主标题**:移动端 2.5rem,小屏幕 2rem
|
||||
- **副标题**:移动端 1.2rem,小屏幕 1rem
|
||||
- **正文**:移动端 1rem,小屏幕 0.95rem
|
||||
|
||||
### 2. 间距规范
|
||||
- **页面间距**:移动端 40px,小屏幕 30px
|
||||
- **容器边距**:移动端 15px,小屏幕 10px
|
||||
- **卡片内边距**:移动端 25px 20px,小屏幕 20px 15px
|
||||
|
||||
### 3. 触摸优化
|
||||
- **按钮最小尺寸**:44px × 44px
|
||||
- **触摸间距**:最小 8px
|
||||
- **触摸反馈**:禁用悬停效果
|
||||
|
||||
## 🚀 性能优化建议
|
||||
|
||||
### 1. 移动端优化
|
||||
```css
|
||||
/* 减少动画复杂度 */
|
||||
@media (max-width: 768px) {
|
||||
.animate {
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.floating-particles {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 触摸设备优化
|
||||
```css
|
||||
/* 触摸友好的交互 */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.hover-effect {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.touch-friendly {
|
||||
min-height: 44px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 高分辨率优化
|
||||
```css
|
||||
/* 高分辨率屏幕优化 */
|
||||
@media (-webkit-min-device-pixel-ratio: 2) {
|
||||
.icon {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🐛 常见问题解决
|
||||
|
||||
### Q: 返回按钮在移动端不显示?
|
||||
A: 已修复,现在返回按钮在移动端菜单中正确显示,带有白色图标和文字。
|
||||
|
||||
### Q: 移动端菜单无法关闭?
|
||||
A: 支持多种关闭方式:
|
||||
- 点击返回按钮
|
||||
- 点击菜单项
|
||||
- 点击外部区域
|
||||
- 按ESC键
|
||||
|
||||
### Q: 移动端动画卡顿?
|
||||
A: 已优化:
|
||||
- 减少动画复杂度
|
||||
- 禁用复杂粒子效果
|
||||
- 优化触摸设备性能
|
||||
|
||||
### Q: 如何自定义移动端样式?
|
||||
A: 使用 `!important` 覆盖,或添加自定义断点:
|
||||
```css
|
||||
@media (max-width: 768px) {
|
||||
.custom-element {
|
||||
/* 自定义样式 */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📱 测试建议
|
||||
|
||||
### 1. 设备测试
|
||||
- iPhone (各种尺寸)
|
||||
- Android (各种尺寸)
|
||||
- iPad (横竖屏)
|
||||
- 桌面端 (各种分辨率)
|
||||
|
||||
### 2. 功能测试
|
||||
- 导航菜单
|
||||
- 触摸交互
|
||||
- 滚动性能
|
||||
- 动画效果
|
||||
|
||||
### 3. 性能测试
|
||||
- 页面加载速度
|
||||
- 滚动流畅度
|
||||
- 内存使用
|
||||
- 电池消耗
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
通过全面的移动端适配,项目现在支持:
|
||||
- ✅ 响应式导航
|
||||
- ✅ 触摸友好交互
|
||||
- ✅ 性能优化
|
||||
- ✅ 多设备兼容
|
||||
- ✅ 无障碍支持
|
||||
|
||||
所有页面都已适配移动端,确保在各种设备上都有良好的用户体验!
|
||||
@@ -23,6 +23,8 @@
|
||||
"@vue/cli-plugin-babel": "^3.0.3",
|
||||
"@vue/cli-service": "^3.0.3",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"less": "^4.4.1",
|
||||
"less-loader": "7.3.0",
|
||||
"postcss-pxtorem": "^6.1.0",
|
||||
"vue-template-compiler": "^2.5.17"
|
||||
},
|
||||
|
||||
@@ -1,785 +0,0 @@
|
||||
/* 动画效果库 - 为项目添加丰富的动画效果 */
|
||||
|
||||
/* ===== 基础动画关键帧 ===== */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
transform: translateY(100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInDown {
|
||||
from {
|
||||
transform: translateY(-100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
transform: translateX(-100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoomIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoomOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 20%, 53%, 80%, 100% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
40%, 43% {
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
70% {
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
90% {
|
||||
transform: translate3d(0, -4px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
10%, 30%, 50%, 70%, 90% {
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
20%, 40%, 60%, 80% {
|
||||
transform: translateX(10px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes swing {
|
||||
20% {
|
||||
transform: rotate(15deg);
|
||||
}
|
||||
40% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
60% {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
80% {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotateIn {
|
||||
from {
|
||||
transform: rotate(-200deg);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: rotate(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flipInX {
|
||||
from {
|
||||
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
|
||||
}
|
||||
60% {
|
||||
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
|
||||
}
|
||||
80% {
|
||||
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
|
||||
}
|
||||
to {
|
||||
transform: perspective(400px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flipInY {
|
||||
from {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
|
||||
opacity: 0;
|
||||
}
|
||||
40% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
|
||||
}
|
||||
60% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
|
||||
}
|
||||
80% {
|
||||
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
|
||||
}
|
||||
to {
|
||||
transform: perspective(400px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes lightSpeedIn {
|
||||
from {
|
||||
transform: translate3d(100%, 0, 0) skewX(-30deg);
|
||||
opacity: 0;
|
||||
}
|
||||
60% {
|
||||
transform: skewX(20deg);
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
transform: skewX(-5deg);
|
||||
}
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rubberBand {
|
||||
from {
|
||||
transform: scale(1);
|
||||
}
|
||||
30% {
|
||||
transform: scaleX(1.25) scaleY(0.75);
|
||||
}
|
||||
40% {
|
||||
transform: scaleX(0.75) scaleY(1.25);
|
||||
}
|
||||
50% {
|
||||
transform: scaleX(1.15) scaleY(0.85);
|
||||
}
|
||||
65% {
|
||||
transform: scaleX(0.95) scaleY(1.05);
|
||||
}
|
||||
75% {
|
||||
transform: scaleX(1.05) scaleY(0.95);
|
||||
}
|
||||
to {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wobble {
|
||||
from {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
15% {
|
||||
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
||||
}
|
||||
30% {
|
||||
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
45% {
|
||||
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
60% {
|
||||
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
||||
}
|
||||
75% {
|
||||
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
||||
}
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tada {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
10%, 20% {
|
||||
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
30%, 50%, 70%, 90% {
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
40%, 60%, 80% {
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes heartBeat {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
14% {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
28% {
|
||||
transform: scale(1);
|
||||
}
|
||||
42% {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
70% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hinge {
|
||||
0% {
|
||||
transform: rotate(0);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
20%, 60% {
|
||||
transform: rotate(80deg);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
40% {
|
||||
transform: rotate(60deg);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
80% {
|
||||
transform: rotate(60deg) translateY(0);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(700px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rollIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rollOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 动画类 ===== */
|
||||
.animate {
|
||||
animation-duration: 1s;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.animate.infinite {
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.animate.delay-1s {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
.animate.delay-2s {
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.animate.delay-3s {
|
||||
animation-delay: 3s;
|
||||
}
|
||||
|
||||
.animate.delay-4s {
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.animate.delay-5s {
|
||||
animation-delay: 5s;
|
||||
}
|
||||
|
||||
.animate.fast {
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.animate.slow {
|
||||
animation-duration: 2s;
|
||||
}
|
||||
|
||||
.animate.slower {
|
||||
animation-duration: 3s;
|
||||
}
|
||||
|
||||
/* ===== 淡入动画 ===== */
|
||||
.fade-in {
|
||||
animation-name: fadeIn;
|
||||
}
|
||||
|
||||
.fade-in-up {
|
||||
animation-name: fadeInUp;
|
||||
}
|
||||
|
||||
.fade-in-down {
|
||||
animation-name: fadeInDown;
|
||||
}
|
||||
|
||||
.fade-in-left {
|
||||
animation-name: fadeInLeft;
|
||||
}
|
||||
|
||||
.fade-in-right {
|
||||
animation-name: fadeInRight;
|
||||
}
|
||||
|
||||
/* ===== 滑入动画 ===== */
|
||||
.slide-in-up {
|
||||
animation-name: slideInUp;
|
||||
}
|
||||
|
||||
.slide-in-down {
|
||||
animation-name: slideInDown;
|
||||
}
|
||||
|
||||
.slide-in-left {
|
||||
animation-name: slideInLeft;
|
||||
}
|
||||
|
||||
.slide-in-right {
|
||||
animation-name: slideInRight;
|
||||
}
|
||||
|
||||
/* ===== 缩放动画 ===== */
|
||||
.zoom-in {
|
||||
animation-name: zoomIn;
|
||||
}
|
||||
|
||||
.zoom-out {
|
||||
animation-name: zoomOut;
|
||||
}
|
||||
|
||||
/* ===== 特殊效果动画 ===== */
|
||||
.bounce {
|
||||
animation-name: bounce;
|
||||
}
|
||||
|
||||
.pulse {
|
||||
animation-name: pulse;
|
||||
}
|
||||
|
||||
.shake {
|
||||
animation-name: shake;
|
||||
}
|
||||
|
||||
.swing {
|
||||
animation-name: swing;
|
||||
}
|
||||
|
||||
.rotate-in {
|
||||
animation-name: rotateIn;
|
||||
}
|
||||
|
||||
.flip-in-x {
|
||||
animation-name: flipInX;
|
||||
}
|
||||
|
||||
.flip-in-y {
|
||||
animation-name: flipInY;
|
||||
}
|
||||
|
||||
.light-speed-in {
|
||||
animation-name: lightSpeedIn;
|
||||
}
|
||||
|
||||
.rubber-band {
|
||||
animation-name: rubberBand;
|
||||
}
|
||||
|
||||
.wobble {
|
||||
animation-name: wobble;
|
||||
}
|
||||
|
||||
.tada {
|
||||
animation-name: tada;
|
||||
}
|
||||
|
||||
.heart-beat {
|
||||
animation-name: heartBeat;
|
||||
}
|
||||
|
||||
.hinge {
|
||||
animation-name: hinge;
|
||||
}
|
||||
|
||||
.roll-in {
|
||||
animation-name: rollIn;
|
||||
}
|
||||
|
||||
.roll-out {
|
||||
animation-name: rollOut;
|
||||
}
|
||||
|
||||
/* ===== 悬停动画 ===== */
|
||||
.hover-lift {
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-lift:hover {
|
||||
transform: translateY(-10px);
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.hover-scale {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-scale:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.hover-rotate {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-rotate:hover {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
|
||||
.hover-glow {
|
||||
transition: box-shadow 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-glow:hover {
|
||||
box-shadow: 0 0 20px rgba(52, 152, 219, 0.5);
|
||||
}
|
||||
|
||||
.hover-bounce {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.hover-bounce:hover {
|
||||
animation: bounce 0.6s ease;
|
||||
}
|
||||
|
||||
/* ===== 滚动触发动画 ===== */
|
||||
.scroll-animate {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease;
|
||||
}
|
||||
|
||||
.scroll-animate.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* ===== 加载动画 ===== */
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #3498db;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-dots {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.loading-dots::after {
|
||||
content: '';
|
||||
animation: dots 1.5s steps(5, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes dots {
|
||||
0%, 20% { content: ''; }
|
||||
40% { content: '.'; }
|
||||
60% { content: '..'; }
|
||||
80%, 100% { content: '...'; }
|
||||
}
|
||||
|
||||
/* ===== 打字机效果 ===== */
|
||||
.typewriter {
|
||||
overflow: hidden;
|
||||
border-right: 2px solid #333;
|
||||
white-space: nowrap;
|
||||
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
from { width: 0; }
|
||||
to { width: 100%; }
|
||||
}
|
||||
|
||||
@keyframes blink-caret {
|
||||
from, to { border-color: transparent; }
|
||||
50% { border-color: #333; }
|
||||
}
|
||||
|
||||
/* ===== 波浪效果 ===== */
|
||||
.wave {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wave::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
||||
animation: wave 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes wave {
|
||||
0% { left: -100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
/* ===== 粒子效果 ===== */
|
||||
.particles {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.particle {
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: #3498db;
|
||||
border-radius: 50%;
|
||||
animation: particle-float 3s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.particle:nth-child(1) { animation-delay: 0s; }
|
||||
.particle:nth-child(2) { animation-delay: 0.5s; }
|
||||
.particle:nth-child(3) { animation-delay: 1s; }
|
||||
.particle:nth-child(4) { animation-delay: 1.5s; }
|
||||
.particle:nth-child(5) { animation-delay: 2s; }
|
||||
|
||||
@keyframes particle-float {
|
||||
0%, 100% {
|
||||
transform: translateY(0) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-20px) scale(1.2);
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 3D翻转效果 ===== */
|
||||
.flip-card {
|
||||
perspective: 1000px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.flip-card-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
transition: transform 0.8s;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.flip-card:hover .flip-card-inner {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
.flip-card-front, .flip-card-back {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.flip-card-back {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
|
||||
/* ===== 渐变背景动画 ===== */
|
||||
.gradient-bg {
|
||||
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
||||
background-size: 400% 400%;
|
||||
animation: gradient-shift 15s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradient-shift {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
/* ===== 霓虹灯效果 ===== */
|
||||
.neon-text {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6, 0 0 25px #0073e6, 0 0 30px #0073e6, 0 0 35px #0073e6;
|
||||
animation: neon-pulse 1.5s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes neon-pulse {
|
||||
from { text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6, 0 0 25px #0073e6, 0 0 30px #0073e6, 0 0 35px #0073e6; }
|
||||
to { text-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #0073e6, 0 0 8px #0073e6, 0 0 10px #0073e6, 0 0 12px #0073e6, 0 0 14px #0073e6; }
|
||||
}
|
||||
|
||||
/* ===== 响应式动画 ===== */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.animate,
|
||||
.hover-lift,
|
||||
.hover-scale,
|
||||
.hover-rotate,
|
||||
.hover-glow,
|
||||
.hover-bounce {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== 动画工具类 ===== */
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
transform: translateY(50px);
|
||||
transition: all 0.8s ease;
|
||||
}
|
||||
|
||||
.animate-on-scroll.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.animate-stagger > * {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.6s ease;
|
||||
}
|
||||
|
||||
.animate-stagger.visible > * {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.animate-stagger.visible > *:nth-child(1) { transition-delay: 0.1s; }
|
||||
.animate-stagger.visible > *:nth-child(2) { transition-delay: 0.2s; }
|
||||
.animate-stagger.visible > *:nth-child(3) { transition-delay: 0.3s; }
|
||||
.animate-stagger.visible > *:nth-child(4) { transition-delay: 0.4s; }
|
||||
.animate-stagger.visible > *:nth-child(5) { transition-delay: 0.5s; }
|
||||
.animate-stagger.visible > *:nth-child(6) { transition-delay: 0.6s; }
|
||||
761
src/assets/css/animations.less
Normal file
761
src/assets/css/animations.less
Normal file
@@ -0,0 +1,761 @@
|
||||
// 动画效果库 - LESS版本
|
||||
@import './variables.less';
|
||||
|
||||
// ===== 动画变量 =====
|
||||
@animation-duration: @animation-duration-base;
|
||||
@animation-timing: @animation-timing-base;
|
||||
@animation-fill-mode: both;
|
||||
|
||||
// ===== 基础动画关键帧 =====
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
transform: translateY(100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInDown {
|
||||
from {
|
||||
transform: translateY(-100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
transform: translateX(-100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
transform: translateX(100px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoomIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes zoomOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: scale(0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 20%, 53%, 80%, 100% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
40%, 43% {
|
||||
transform: translate3d(0, -30px, 0);
|
||||
}
|
||||
70% {
|
||||
transform: translate3d(0, -15px, 0);
|
||||
}
|
||||
90% {
|
||||
transform: translate3d(0, -4px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
50% {
|
||||
transform: scale3d(1.05, 1.05, 1.05);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
10%, 30%, 50%, 70%, 90% {
|
||||
transform: translate3d(-10px, 0, 0);
|
||||
}
|
||||
20%, 40%, 60%, 80% {
|
||||
transform: translate3d(10px, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes swing {
|
||||
20% {
|
||||
transform: rotate(15deg);
|
||||
}
|
||||
40% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
60% {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
80% {
|
||||
transform: rotate(-5deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes flip {
|
||||
0% {
|
||||
transform: perspective(400px) rotateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: perspective(400px) rotateY(90deg);
|
||||
}
|
||||
60% {
|
||||
transform: perspective(400px) rotateY(180deg);
|
||||
}
|
||||
80% {
|
||||
transform: perspective(400px) rotateY(270deg);
|
||||
}
|
||||
100% {
|
||||
transform: perspective(400px) rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes lightSpeedIn {
|
||||
from {
|
||||
transform: translate3d(100%, 0, 0) skewX(-30deg);
|
||||
opacity: 0;
|
||||
}
|
||||
60% {
|
||||
transform: skewX(20deg);
|
||||
opacity: 1;
|
||||
}
|
||||
80% {
|
||||
transform: skewX(-5deg);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rubberBand {
|
||||
from {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
30% {
|
||||
transform: scale3d(1.25, 0.75, 1);
|
||||
}
|
||||
40% {
|
||||
transform: scale3d(0.75, 1.25, 1);
|
||||
}
|
||||
50% {
|
||||
transform: scale3d(1.15, 0.85, 1);
|
||||
}
|
||||
65% {
|
||||
transform: scale3d(0.95, 1.05, 1);
|
||||
}
|
||||
75% {
|
||||
transform: scale3d(1.05, 0.95, 1);
|
||||
}
|
||||
to {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wobble {
|
||||
0% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
15% {
|
||||
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
|
||||
}
|
||||
30% {
|
||||
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
45% {
|
||||
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
60% {
|
||||
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
|
||||
}
|
||||
75% {
|
||||
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tada {
|
||||
0% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
10%, 20% {
|
||||
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
30%, 50%, 70%, 90% {
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
|
||||
}
|
||||
40%, 60%, 80% {
|
||||
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
|
||||
}
|
||||
100% {
|
||||
transform: scale3d(1, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes heartBeat {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
14% {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
28% {
|
||||
transform: scale(1);
|
||||
}
|
||||
42% {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
70% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hinge {
|
||||
0% {
|
||||
transform: rotate(0);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
20%, 60% {
|
||||
transform: rotate(80deg);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
40%, 80% {
|
||||
transform: rotate(60deg);
|
||||
transform-origin: top left;
|
||||
animation-timing-function: ease-in-out;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(0, 700px, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes roll {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 基础动画类 =====
|
||||
.animate {
|
||||
animation-duration: @animation-duration;
|
||||
animation-fill-mode: @animation-fill-mode;
|
||||
animation-timing-function: @animation-timing;
|
||||
}
|
||||
|
||||
// 淡入动画
|
||||
.fade-in { animation-name: fadeIn; }
|
||||
.fade-in-up { animation-name: fadeInUp; }
|
||||
.fade-in-down { animation-name: fadeInDown; }
|
||||
.fade-in-left { animation-name: fadeInLeft; }
|
||||
.fade-in-right { animation-name: fadeInRight; }
|
||||
|
||||
// 滑入动画
|
||||
.slide-in-up { animation-name: slideInUp; }
|
||||
.slide-in-down { animation-name: slideInDown; }
|
||||
.slide-in-left { animation-name: slideInLeft; }
|
||||
.slide-in-right { animation-name: slideInRight; }
|
||||
|
||||
// 缩放动画
|
||||
.zoom-in { animation-name: zoomIn; }
|
||||
.zoom-out { animation-name: zoomOut; }
|
||||
|
||||
// 特殊动画
|
||||
.bounce { animation-name: bounce; }
|
||||
.pulse { animation-name: pulse; }
|
||||
.shake { animation-name: shake; }
|
||||
.swing { animation-name: swing; }
|
||||
.rotate { animation-name: rotate; }
|
||||
.flip { animation-name: flip; }
|
||||
.light-speed-in { animation-name: lightSpeedIn; }
|
||||
.rubber-band { animation-name: rubberBand; }
|
||||
.wobble { animation-name: wobble; }
|
||||
.tada { animation-name: tada; }
|
||||
.heart-beat { animation-name: heartBeat; }
|
||||
.hinge { animation-name: hinge; }
|
||||
.roll { animation-name: roll; }
|
||||
|
||||
// ===== 动画时长 =====
|
||||
.duration-0_5s { animation-duration: 0.5s; }
|
||||
.duration-1s { animation-duration: 1s; }
|
||||
.duration-1_5s { animation-duration: 1.5s; }
|
||||
.duration-2s { animation-duration: 2s; }
|
||||
.duration-3s { animation-duration: 3s; }
|
||||
|
||||
// ===== 动画延迟 =====
|
||||
.delay-0_5s { animation-delay: 0.5s; }
|
||||
.delay-1s { animation-delay: 1s; }
|
||||
.delay-1_5s { animation-delay: 1.5s; }
|
||||
.delay-2s { animation-delay: 2s; }
|
||||
.delay-3s { animation-delay: 3s; }
|
||||
|
||||
// ===== 动画重复 =====
|
||||
.infinite { animation-iteration-count: infinite; }
|
||||
.repeat-2 { animation-iteration-count: 2; }
|
||||
.repeat-3 { animation-iteration-count: 3; }
|
||||
|
||||
// ===== 悬停动画效果 =====
|
||||
.hover-lift {
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.hover-scale {
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
.hover-glow {
|
||||
transition: box-shadow 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 20px rgba(0, 123, 255, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.hover-rotate {
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
transform: rotate(5deg);
|
||||
}
|
||||
}
|
||||
|
||||
.hover-bounce {
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
animation: bounce 0.6s ease;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 滚动触发动画 =====
|
||||
.scroll-animate {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease;
|
||||
|
||||
&.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 交错动画 =====
|
||||
.animate-stagger {
|
||||
> * {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: all 0.6s ease;
|
||||
|
||||
&:nth-child(1) { transition-delay: 0.1s; }
|
||||
&:nth-child(2) { transition-delay: 0.2s; }
|
||||
&:nth-child(3) { transition-delay: 0.3s; }
|
||||
&:nth-child(4) { transition-delay: 0.4s; }
|
||||
&:nth-child(5) { transition-delay: 0.5s; }
|
||||
&:nth-child(6) { transition-delay: 0.6s; }
|
||||
|
||||
&.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 加载指示器 =====
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #3498db;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
// ===== 打字机效果 =====
|
||||
.typewriter {
|
||||
overflow: hidden;
|
||||
border-right: 2px solid #000;
|
||||
white-space: nowrap;
|
||||
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
|
||||
}
|
||||
|
||||
@keyframes typing {
|
||||
from { width: 0; }
|
||||
to { width: 100%; }
|
||||
}
|
||||
|
||||
@keyframes blink-caret {
|
||||
from, to { border-color: transparent; }
|
||||
50% { border-color: #000; }
|
||||
}
|
||||
|
||||
// ===== 波浪效果 =====
|
||||
.wave {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.3) 50%, transparent 70%);
|
||||
animation: wave 2s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes wave {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
// ===== 粒子效果 =====
|
||||
.particles {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
animation: float 6s infinite;
|
||||
}
|
||||
|
||||
&::before {
|
||||
left: 20%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
&::after {
|
||||
right: 20%;
|
||||
animation-delay: 3s;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px) rotate(0deg); opacity: 1; }
|
||||
50% { transform: translateY(-20px) rotate(180deg); opacity: 0.5; }
|
||||
}
|
||||
|
||||
// ===== 3D翻转卡片 =====
|
||||
.flip-card {
|
||||
perspective: 1000px;
|
||||
|
||||
.flip-card-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
transition: transform 0.6s;
|
||||
transform-style: preserve-3d;
|
||||
|
||||
&:hover {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.flip-card-front,
|
||||
.flip-card-back {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.flip-card-back {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 渐变背景动画 =====
|
||||
.gradient-bg {
|
||||
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
||||
background-size: 400% 400%;
|
||||
animation: gradient 15s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradient {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
// ===== 霓虹文字效果 =====
|
||||
.neon-text {
|
||||
color: #fff;
|
||||
text-shadow:
|
||||
0 0 5px #fff,
|
||||
0 0 10px #fff,
|
||||
0 0 15px #0073e6,
|
||||
0 0 20px #0073e6,
|
||||
0 0 25px #0073e6,
|
||||
0 0 30px #0073e6,
|
||||
0 0 35px #0073e6;
|
||||
animation: neon-pulse 1.5s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes neon-pulse {
|
||||
from { text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6, 0 0 25px #0073e6, 0 0 30px #0073e6, 0 0 35px #0073e6; }
|
||||
to { text-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #0073e6, 0 0 8px #0073e6, 0 0 10px #0073e6, 0 0 12px #0073e6, 0 0 14px #0073e6; }
|
||||
}
|
||||
|
||||
// ===== 滚动进度条 =====
|
||||
.scroll-progress-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 0%;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #0073e6, #00d4ff);
|
||||
z-index: 9999;
|
||||
transition: width 0.1s ease;
|
||||
}
|
||||
|
||||
// ===== 视差滚动元素 =====
|
||||
.parallax {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.parallax-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 120%;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
transform: translateZ(0);
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 浮动粒子 =====
|
||||
.floating-particles {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
|
||||
.floating-particle {
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 50%;
|
||||
animation: float-particle 8s infinite linear;
|
||||
|
||||
&:nth-child(1) { left: 10%; animation-delay: 0s; animation-duration: 8s; }
|
||||
&:nth-child(2) { left: 20%; animation-delay: 1s; animation-duration: 10s; }
|
||||
&:nth-child(3) { left: 30%; animation-delay: 2s; animation-duration: 12s; }
|
||||
&:nth-child(4) { left: 40%; animation-delay: 3s; animation-duration: 9s; }
|
||||
&:nth-child(5) { left: 50%; animation-delay: 4s; animation-duration: 11s; }
|
||||
&:nth-child(6) { left: 60%; animation-delay: 5s; animation-duration: 7s; }
|
||||
&:nth-child(7) { left: 70%; animation-delay: 6s; animation-duration: 13s; }
|
||||
&:nth-child(8) { left: 80%; animation-delay: 7s; animation-duration: 8s; }
|
||||
&:nth-child(9) { left: 90%; animation-delay: 8s; animation-duration: 10s; }
|
||||
&:nth-child(10) { left: 95%; animation-delay: 9s; animation-duration: 12s; }
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float-particle {
|
||||
0% {
|
||||
transform: translateY(100vh) scale(0);
|
||||
opacity: 0;
|
||||
}
|
||||
10% {
|
||||
opacity: 1;
|
||||
}
|
||||
90% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100px) scale(1);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 文字发光效果 =====
|
||||
.text-glow {
|
||||
text-shadow:
|
||||
0 0 5px currentColor,
|
||||
0 0 10px currentColor,
|
||||
0 0 15px currentColor,
|
||||
0 0 20px currentColor;
|
||||
animation: text-glow-pulse 2s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
@keyframes text-glow-pulse {
|
||||
from { text-shadow: 0 0 5px currentColor, 0 0 10px currentColor, 0 0 15px currentColor, 0 0 20px currentColor; }
|
||||
to { text-shadow: 0 0 10px currentColor, 0 0 20px currentColor, 0 0 30px currentColor, 0 0 40px currentColor; }
|
||||
}
|
||||
|
||||
// ===== 响应式动画考虑 =====
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 移动端动画优化 =====
|
||||
@media (max-width: 768px) {
|
||||
.floating-particles {
|
||||
display: none; // 移动端隐藏浮动粒子以提升性能
|
||||
}
|
||||
|
||||
.animate {
|
||||
animation-duration: 0.8s; // 移动端减少动画时长
|
||||
}
|
||||
|
||||
.scroll-animate {
|
||||
transform: translateY(20px); // 移动端减少移动距离
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 性能优化 =====
|
||||
.animate,
|
||||
.hover-lift,
|
||||
.hover-scale,
|
||||
.hover-glow,
|
||||
.hover-rotate,
|
||||
.hover-bounce {
|
||||
will-change: transform, opacity;
|
||||
transform: translate3d(0, 0, 0); // 启用硬件加速
|
||||
}
|
||||
|
||||
// ===== 动画工具类 =====
|
||||
.animation-paused { animation-play-state: paused; }
|
||||
.animation-running { animation-play-state: running; }
|
||||
.animation-reverse { animation-direction: reverse; }
|
||||
.animation-alternate { animation-direction: alternate; }
|
||||
.animation-alternate-reverse { animation-direction: alternate-reverse; }
|
||||
@@ -1,39 +0,0 @@
|
||||
|
||||
|
||||
.scrollToContentWrapper {
|
||||
height: 6em;
|
||||
text-align: center;
|
||||
z-index: 5000;
|
||||
}
|
||||
|
||||
.scrollToContentWrapper>a.scrollToContent {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-top: -3em;
|
||||
background: lightyellow;
|
||||
width: 4.8em;
|
||||
height: 4.8em;
|
||||
line-height: 5.6em;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.scrollToContentWrapper>a.scrollToContent:hover {
|
||||
background-color: #000 !important;
|
||||
border-color: #111;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.scrollToContentWrapper>a.scrollToContent:hover img {
|
||||
-webkit-filter: invert(100%);
|
||||
filter: invert(100%);
|
||||
}
|
||||
|
||||
.scrollToContentWrapper>a.scrollToContent>img {
|
||||
height: 1.0em;
|
||||
}
|
||||
40
src/assets/css/common.less
Normal file
40
src/assets/css/common.less
Normal file
@@ -0,0 +1,40 @@
|
||||
// 通用样式 - LESS版本
|
||||
@import './variables.less';
|
||||
|
||||
.scrollToContentWrapper {
|
||||
height: 6em;
|
||||
text-align: center;
|
||||
z-index: 5000;
|
||||
|
||||
> a.scrollToContent {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-top: -3em;
|
||||
background: lightyellow;
|
||||
width: 4.8em;
|
||||
height: 4.8em;
|
||||
line-height: 5.6em;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
|
||||
&:hover {
|
||||
background-color: #000 !important;
|
||||
border-color: #111;
|
||||
text-decoration: none;
|
||||
|
||||
img {
|
||||
-webkit-filter: invert(100%);
|
||||
filter: invert(100%);
|
||||
}
|
||||
}
|
||||
|
||||
> img {
|
||||
height: 1.0em;
|
||||
}
|
||||
}
|
||||
}
|
||||
933
src/assets/css/common_mobile.less
Normal file
933
src/assets/css/common_mobile.less
Normal file
@@ -0,0 +1,933 @@
|
||||
// 通用移动端适配样式 - 适用于所有页面 - LESS版本
|
||||
@import './variables.less';
|
||||
|
||||
// ===== 移动端断点变量 =====
|
||||
// 使用全局变量文件中的断点
|
||||
|
||||
// ===== 移动端基础适配 =====
|
||||
@media (max-width: @mobile-breakpoint) {
|
||||
// 页面横幅移动端适配
|
||||
.page-banner {
|
||||
padding: 60px 0 40px !important;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 2.5rem !important;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1.2rem !important;
|
||||
line-height: 1.4 !important;
|
||||
}
|
||||
|
||||
// 容器移动端适配
|
||||
.container {
|
||||
padding: 0 15px !important;
|
||||
}
|
||||
|
||||
// 标题移动端适配
|
||||
.section-title {
|
||||
font-size: 2rem !important;
|
||||
line-height: 1.3 !important;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1.1rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
// 网格布局移动端适配
|
||||
.grid,
|
||||
.advantages-grid,
|
||||
.areas-grid,
|
||||
.services-grid,
|
||||
.team-grid,
|
||||
.contact-grid,
|
||||
.tech-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 20px !important;
|
||||
}
|
||||
|
||||
// 卡片移动端适配
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-item,
|
||||
.team-member,
|
||||
.contact-card,
|
||||
.tech-layer {
|
||||
padding: 25px 20px !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
// 内容区域移动端适配
|
||||
.content-section {
|
||||
margin-bottom: 40px !important;
|
||||
}
|
||||
|
||||
.section-text {
|
||||
font-size: 1rem !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
|
||||
// 图标移动端适配
|
||||
.icon,
|
||||
.service-icon,
|
||||
.advantage-icon,
|
||||
.area-icon,
|
||||
.contact-icon {
|
||||
font-size: 2.5rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
// 列表移动端适配
|
||||
.feature-list,
|
||||
.advantage-features,
|
||||
.area-features {
|
||||
padding-left: 20px !important;
|
||||
|
||||
li {
|
||||
margin-bottom: 8px !important;
|
||||
font-size: 0.95rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 时间线移动端适配
|
||||
.timeline {
|
||||
padding-left: 20px !important;
|
||||
|
||||
.timeline-item {
|
||||
margin-bottom: 30px !important;
|
||||
padding-left: 20px !important;
|
||||
|
||||
.timeline-date {
|
||||
font-size: 0.9rem !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.timeline-title {
|
||||
font-size: 1.1rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
font-size: 0.95rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计数字移动端适配
|
||||
.stats-section {
|
||||
padding: 40px 0 !important;
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr) !important;
|
||||
gap: 20px !important;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center !important;
|
||||
padding: 20px 15px !important;
|
||||
|
||||
.stat-number {
|
||||
font-size: 2rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 团队介绍移动端适配
|
||||
.team-section {
|
||||
.team-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 25px !important;
|
||||
}
|
||||
|
||||
.team-member {
|
||||
text-align: center !important;
|
||||
|
||||
.member-photo {
|
||||
width: 120px !important;
|
||||
height: 120px !important;
|
||||
margin: 0 auto 15px !important;
|
||||
}
|
||||
|
||||
.member-name {
|
||||
font-size: 1.2rem !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.member-position {
|
||||
font-size: 0.9rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.member-description {
|
||||
font-size: 0.9rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 联系信息移动端适配
|
||||
.contact-section {
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
gap: 25px !important;
|
||||
}
|
||||
|
||||
.contact-info {
|
||||
text-align: center !important;
|
||||
|
||||
.contact-icon {
|
||||
font-size: 2rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.contact-title {
|
||||
font-size: 1.1rem !important;
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
|
||||
.contact-detail {
|
||||
font-size: 0.95rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 技术栈移动端适配
|
||||
.tech-section {
|
||||
.tech-grid {
|
||||
grid-template-columns: repeat(2, 1fr) !important;
|
||||
gap: 15px !important;
|
||||
}
|
||||
|
||||
.tech-layer {
|
||||
padding: 20px 15px !important;
|
||||
text-align: center !important;
|
||||
|
||||
.tech-icon {
|
||||
font-size: 2rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.tech-name {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 解决方案移动端适配
|
||||
.solutions-section {
|
||||
.solution-item {
|
||||
margin-bottom: 30px !important;
|
||||
padding: 20px !important;
|
||||
|
||||
.solution-icon {
|
||||
font-size: 2.5rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.solution-title {
|
||||
font-size: 1.3rem !important;
|
||||
margin-bottom: 12px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.solution-description {
|
||||
font-size: 0.95rem !important;
|
||||
line-height: 1.6 !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 优势特点移动端适配
|
||||
.advantages-section {
|
||||
.advantage-item {
|
||||
margin-bottom: 25px !important;
|
||||
padding: 20px !important;
|
||||
text-align: center !important;
|
||||
|
||||
.advantage-icon {
|
||||
font-size: 2.5rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.advantage-title {
|
||||
font-size: 1.2rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.advantage-description {
|
||||
font-size: 0.9rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 服务领域移动端适配
|
||||
.areas-section {
|
||||
.area-item {
|
||||
margin-bottom: 25px !important;
|
||||
padding: 20px !important;
|
||||
text-align: center !important;
|
||||
|
||||
.area-icon {
|
||||
font-size: 2.5rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.area-title {
|
||||
font-size: 1.2rem !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.area-description {
|
||||
font-size: 0.9rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
.area-features {
|
||||
margin-top: 15px !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮移动端适配
|
||||
.btn,
|
||||
.button {
|
||||
padding: 12px 24px !important;
|
||||
font-size: 16px !important;
|
||||
min-height: 44px !important; // 触摸友好尺寸
|
||||
width: 100% !important; // 移动端全宽按钮
|
||||
|
||||
&.btn-large {
|
||||
padding: 15px 30px !important;
|
||||
font-size: 18px !important;
|
||||
}
|
||||
|
||||
&.btn-small {
|
||||
padding: 8px 16px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
&.btn-block {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 表单移动端适配
|
||||
.form-section {
|
||||
.form-group {
|
||||
margin-bottom: 20px !important;
|
||||
|
||||
label {
|
||||
display: block !important;
|
||||
margin-bottom: 8px !important;
|
||||
font-weight: 500 !important;
|
||||
font-size: 0.95rem !important;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select {
|
||||
width: 100% !important;
|
||||
padding: 12px !important;
|
||||
font-size: 16px !important; // 防止iOS缩放
|
||||
border: 1px solid #ddd !important;
|
||||
border-radius: 4px !important;
|
||||
min-height: 44px !important; // 触摸友好尺寸
|
||||
|
||||
&:focus {
|
||||
outline: none !important;
|
||||
border-color: #3498db !important;
|
||||
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 100px !important;
|
||||
resize: vertical !important;
|
||||
}
|
||||
|
||||
.form-help {
|
||||
font-size: 0.85rem !important;
|
||||
color: #666 !important;
|
||||
margin-top: 5px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
text-align: center !important;
|
||||
margin-top: 30px !important;
|
||||
|
||||
.btn {
|
||||
margin: 0 5px 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 图片移动端适配
|
||||
.image-section {
|
||||
img {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.image-caption {
|
||||
font-size: 0.9rem !important;
|
||||
color: #666 !important;
|
||||
text-align: center !important;
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 视频移动端适配
|
||||
.video-section {
|
||||
.video-container {
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
height: 0 !important;
|
||||
padding-bottom: 56.25% !important; // 16:9 比例
|
||||
|
||||
iframe,
|
||||
video {
|
||||
position: absolute !important;
|
||||
top: 0 !important;
|
||||
left: 0 !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 表格移动端适配
|
||||
.table-section {
|
||||
.table-responsive {
|
||||
overflow-x: auto !important;
|
||||
-webkit-overflow-scrolling: touch !important;
|
||||
|
||||
table {
|
||||
min-width: 600px !important;
|
||||
font-size: 0.9rem !important;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 8px 12px !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页移动端适配
|
||||
.pagination {
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
flex-wrap: wrap !important;
|
||||
gap: 5px !important;
|
||||
margin: 30px 0 !important;
|
||||
|
||||
.page-item {
|
||||
.page-link {
|
||||
padding: 8px 12px !important;
|
||||
font-size: 14px !important;
|
||||
min-width: 40px !important;
|
||||
text-align: center !important;
|
||||
border-radius: 4px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 面包屑移动端适配
|
||||
.breadcrumb {
|
||||
padding: 10px 0 !important;
|
||||
font-size: 0.9rem !important;
|
||||
|
||||
.breadcrumb-item {
|
||||
margin-right: 8px !important;
|
||||
|
||||
&:not(:last-child)::after {
|
||||
content: '>' !important;
|
||||
margin-left: 8px !important;
|
||||
color: #999 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签移动端适配
|
||||
.tags {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
gap: 8px !important;
|
||||
margin: 15px 0 !important;
|
||||
|
||||
.tag {
|
||||
padding: 4px 8px !important;
|
||||
font-size: 0.8rem !important;
|
||||
border-radius: 12px !important;
|
||||
background: #f0f0f0 !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 警告框移动端适配
|
||||
.alert {
|
||||
padding: 15px !important;
|
||||
margin: 20px 0 !important;
|
||||
border-radius: 4px !important;
|
||||
font-size: 0.95rem !important;
|
||||
|
||||
&.alert-success {
|
||||
background: #d4edda !important;
|
||||
border: 1px solid #c3e6cb !important;
|
||||
color: #155724 !important;
|
||||
}
|
||||
|
||||
&.alert-warning {
|
||||
background: #fff3cd !important;
|
||||
border: 1px solid #ffeaa7 !important;
|
||||
color: #856404 !important;
|
||||
}
|
||||
|
||||
&.alert-danger {
|
||||
background: #f8d7da !important;
|
||||
border: 1px solid #f5c6cb !important;
|
||||
color: #721c24 !important;
|
||||
}
|
||||
|
||||
&.alert-info {
|
||||
background: #d1ecf1 !important;
|
||||
border: 1px solid #bee5eb !important;
|
||||
color: #0c5460 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 进度条移动端适配
|
||||
.progress {
|
||||
height: 20px !important;
|
||||
margin: 15px 0 !important;
|
||||
border-radius: 10px !important;
|
||||
overflow: hidden !important;
|
||||
|
||||
.progress-bar {
|
||||
height: 100% !important;
|
||||
border-radius: 10px !important;
|
||||
font-size: 0.8rem !important;
|
||||
line-height: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 模态框移动端适配
|
||||
.modal {
|
||||
.modal-dialog {
|
||||
margin: 10px !important;
|
||||
max-width: calc(100% - 20px) !important;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 15px 20px !important;
|
||||
|
||||
.modal-title {
|
||||
font-size: 1.2rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 20px !important;
|
||||
font-size: 0.95rem !important;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 15px 20px !important;
|
||||
|
||||
.btn {
|
||||
margin: 0 5px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 工具提示移动端适配
|
||||
.tooltip {
|
||||
font-size: 0.85rem !important;
|
||||
max-width: 200px !important;
|
||||
}
|
||||
|
||||
// 弹出框移动端适配
|
||||
.popover {
|
||||
max-width: 250px !important;
|
||||
font-size: 0.9rem !important;
|
||||
|
||||
.popover-header {
|
||||
font-size: 1rem !important;
|
||||
padding: 10px 15px !important;
|
||||
}
|
||||
|
||||
.popover-body {
|
||||
padding: 10px 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 手风琴移动端适配
|
||||
.accordion {
|
||||
.accordion-item {
|
||||
margin-bottom: 10px !important;
|
||||
border-radius: 8px !important;
|
||||
overflow: hidden !important;
|
||||
|
||||
.accordion-header {
|
||||
.accordion-button {
|
||||
padding: 15px 20px !important;
|
||||
font-size: 1rem !important;
|
||||
|
||||
&:not(.collapsed) {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-body {
|
||||
padding: 15px 20px !important;
|
||||
font-size: 0.95rem !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签页移动端适配
|
||||
.nav-tabs {
|
||||
flex-wrap: wrap !important;
|
||||
|
||||
.nav-item {
|
||||
margin-bottom: 5px !important;
|
||||
|
||||
.nav-link {
|
||||
padding: 8px 12px !important;
|
||||
font-size: 0.9rem !important;
|
||||
border-radius: 4px !important;
|
||||
|
||||
&.active {
|
||||
background-color: #007bff !important;
|
||||
border-color: #007bff !important;
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导航栏移动端适配
|
||||
.navbar {
|
||||
.navbar-brand {
|
||||
font-size: 1.2rem !important;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
.nav-link {
|
||||
padding: 10px 15px !important;
|
||||
font-size: 0.95rem !important;
|
||||
border-bottom: 1px solid #eee !important;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f9fa !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 侧边栏移动端适配
|
||||
.sidebar {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
left: -100% !important;
|
||||
width: 80% !important;
|
||||
height: 100vh !important;
|
||||
background: white !important;
|
||||
z-index: 1000 !important;
|
||||
transition: left 0.3s ease !important;
|
||||
overflow-y: auto !important;
|
||||
|
||||
&.active {
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 20px !important;
|
||||
border-bottom: 1px solid #eee !important;
|
||||
|
||||
.close-sidebar {
|
||||
float: right !important;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
font-size: 1.5rem !important;
|
||||
cursor: pointer !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-body {
|
||||
padding: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 页脚移动端适配
|
||||
.footer {
|
||||
padding: 40px 0 20px !important;
|
||||
text-align: center !important;
|
||||
|
||||
.footer-content {
|
||||
margin-bottom: 30px !important;
|
||||
|
||||
.footer-section {
|
||||
margin-bottom: 25px !important;
|
||||
|
||||
.footer-title {
|
||||
font-size: 1.1rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
list-style: none !important;
|
||||
padding: 0 !important;
|
||||
|
||||
li {
|
||||
margin-bottom: 8px !important;
|
||||
|
||||
a {
|
||||
color: #666 !important;
|
||||
text-decoration: none !important;
|
||||
font-size: 0.9rem !important;
|
||||
|
||||
&:hover {
|
||||
color: #333 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
border-top: 1px solid #eee !important;
|
||||
padding-top: 20px !important;
|
||||
font-size: 0.85rem !important;
|
||||
color: #999 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 平板端适配 =====
|
||||
@media (min-width: @mobile-breakpoint + 1) and (max-width: @tablet-breakpoint) {
|
||||
.container {
|
||||
padding: 0 30px !important;
|
||||
}
|
||||
|
||||
.grid,
|
||||
.advantages-grid,
|
||||
.areas-grid,
|
||||
.services-grid,
|
||||
.team-grid,
|
||||
.contact-grid,
|
||||
.tech-grid {
|
||||
grid-template-columns: repeat(2, 1fr) !important;
|
||||
gap: 25px !important;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(4, 1fr) !important;
|
||||
}
|
||||
|
||||
.tech-grid {
|
||||
grid-template-columns: repeat(3, 1fr) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 小屏幕移动端适配 =====
|
||||
@media (max-width: @small-mobile) {
|
||||
.container {
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 2rem !important;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.8rem !important;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
}
|
||||
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-item,
|
||||
.team-member,
|
||||
.contact-card,
|
||||
.tech-layer {
|
||||
padding: 20px 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 超小屏幕移动端适配 =====
|
||||
@media (max-width: @xs-mobile) {
|
||||
.container {
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 1.8rem !important;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.6rem !important;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 0.9rem !important;
|
||||
}
|
||||
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-item,
|
||||
.team-member,
|
||||
.contact-card,
|
||||
.tech-layer {
|
||||
padding: 15px 12px !important;
|
||||
}
|
||||
|
||||
.btn,
|
||||
.button {
|
||||
padding: 8px 16px !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 触摸设备优化 =====
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
// 触摸设备禁用悬停效果
|
||||
.btn:hover,
|
||||
.button:hover,
|
||||
.card:hover,
|
||||
.advantage-card:hover,
|
||||
.area-card:hover,
|
||||
.service-item:hover,
|
||||
.team-member:hover,
|
||||
.contact-card:hover,
|
||||
.tech-layer:hover {
|
||||
transform: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
// 触摸设备增加触摸反馈
|
||||
.btn,
|
||||
.button,
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-item,
|
||||
.team-member,
|
||||
.contact-card,
|
||||
.tech-layer {
|
||||
-webkit-tap-highlight-color: rgba(52, 152, 219, 0.3) !important;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98) !important;
|
||||
transition: transform 0.1s ease !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 高分辨率屏幕适配 =====
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
.icon,
|
||||
.service-icon,
|
||||
.advantage-icon,
|
||||
.area-icon,
|
||||
.contact-icon {
|
||||
image-rendering: -webkit-optimize-contrast !important;
|
||||
image-rendering: crisp-edges !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 横屏模式适配 =====
|
||||
@media (orientation: landscape) and (max-height: 500px) {
|
||||
.page-banner {
|
||||
padding: 30px 0 20px !important;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 2rem !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1rem !important;
|
||||
margin-bottom: 20px !important;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 30px 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 打印样式 =====
|
||||
@media print {
|
||||
.mobile-nav,
|
||||
.sidebar,
|
||||
.modal,
|
||||
.tooltip,
|
||||
.popover {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 20px 0 !important;
|
||||
page-break-inside: avoid !important;
|
||||
}
|
||||
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-item,
|
||||
.team-member,
|
||||
.contact-card,
|
||||
.tech-layer {
|
||||
page-break-inside: avoid !important;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
251
src/assets/css/content_pages.less
Normal file
251
src/assets/css/content_pages.less
Normal file
@@ -0,0 +1,251 @@
|
||||
/*PAGE*/
|
||||
|
||||
/* 导入全局变量 */
|
||||
@import './variables.less';
|
||||
|
||||
/* 使用 LESS 变量定义响应式断点 */
|
||||
@breakpoint-xs: 380px;
|
||||
@breakpoint-sm: 480px;
|
||||
@breakpoint-md: 620px;
|
||||
@breakpoint-lg: 768px;
|
||||
@breakpoint-xl: 992px;
|
||||
@breakpoint-xxl: 1200px;
|
||||
@breakpoint-xxxl: 1500px;
|
||||
@breakpoint-xxxxl: 1600px;
|
||||
|
||||
/* 间距变量 */
|
||||
@spacing-xs: 0.5em;
|
||||
@spacing-sm: 1em;
|
||||
@spacing-md: 1.5em;
|
||||
@spacing-lg: 2em;
|
||||
@spacing-xl: 3em;
|
||||
@spacing-xxl: 4em;
|
||||
@spacing-xxxl: 5em;
|
||||
@spacing-xxxxl: 7em;
|
||||
|
||||
/* 字体大小变量 */
|
||||
@font-size-xs: 0.9em;
|
||||
@font-size-sm: 1.2em;
|
||||
@font-size-md: 1.5em;
|
||||
@font-size-lg: 2.5em;
|
||||
@font-size-xl: 3em;
|
||||
|
||||
/* 布局变量 */
|
||||
@sidebar-width: 25%;
|
||||
@content-width: 75%;
|
||||
@content-padding: 4em;
|
||||
@sidebar-padding: 5em;
|
||||
|
||||
.contentPage {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
vertical-align: top;
|
||||
margin: 0 auto;
|
||||
padding-top: @spacing-xxxxl;
|
||||
min-height: 100vh;
|
||||
|
||||
/* 容器查询支持 */
|
||||
container-type: inline-size;
|
||||
container-name: content-page;
|
||||
}
|
||||
|
||||
/* CONTENT TABLES */
|
||||
|
||||
.contentTableLeft {
|
||||
width: @sidebar-width;
|
||||
padding-left: @sidebar-padding;
|
||||
padding-top: @spacing-xl;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
width: @content-width;
|
||||
padding-top: 3.5em;
|
||||
padding-left: @content-padding;
|
||||
padding-right: @content-padding;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* 使用容器查询替代媒体查询 */
|
||||
@container content-page (max-width: @breakpoint-xxxxl) {
|
||||
.contentTableRight {
|
||||
padding-right: 8em;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-xxxl) {
|
||||
.contentTableRight {
|
||||
padding-right: 6em;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-xl;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-xxl) {
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-lg;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bread {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-left: @spacing-xl;
|
||||
padding-top: @spacing-xl;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
padding-left: @spacing-xl;
|
||||
padding-right: @spacing-xl;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-xl) {
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-md;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bread {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-left: @spacing-lg;
|
||||
padding-top: @spacing-lg;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
padding-left: @spacing-lg;
|
||||
padding-right: @spacing-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-lg) {
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-sm;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bread {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-left: @spacing-md;
|
||||
padding-top: @spacing-md;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
padding-left: @spacing-md;
|
||||
padding-right: @spacing-md;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-md) {
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-xs;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bread {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-left: @spacing-sm;
|
||||
padding-top: @spacing-sm;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
padding-left: @spacing-sm;
|
||||
padding-right: @spacing-sm;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-sm) {
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-xs;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bread {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-left: @spacing-xs;
|
||||
padding-top: @spacing-xs;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
padding-left: @spacing-xs;
|
||||
padding-right: @spacing-xs;
|
||||
}
|
||||
}
|
||||
|
||||
@container content-page (max-width: @breakpoint-xs) {
|
||||
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
|
||||
font-size: @font-size-xs;
|
||||
}
|
||||
|
||||
.contentPage .contentPageBanner .bannerBox .bread {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-left: @spacing-xs;
|
||||
padding-top: @spacing-xs;
|
||||
}
|
||||
|
||||
.contentTableRight {
|
||||
padding-left: @spacing-xs;
|
||||
padding-right: @spacing-xs;
|
||||
}
|
||||
}
|
||||
|
||||
/* 响应式布局调整 */
|
||||
@media (max-width: @breakpoint-lg) {
|
||||
.contentPage {
|
||||
padding-top: @spacing-xxl;
|
||||
}
|
||||
|
||||
.contentTableLeft,
|
||||
.contentTableRight {
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-bottom: @spacing-lg;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @breakpoint-md) {
|
||||
.contentPage {
|
||||
padding-top: @spacing-xl;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-bottom: @spacing-md;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @breakpoint-sm) {
|
||||
.contentPage {
|
||||
padding-top: @spacing-lg;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-bottom: @spacing-sm;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @breakpoint-xs) {
|
||||
.contentPage {
|
||||
padding-top: @spacing-md;
|
||||
}
|
||||
|
||||
.contentTableLeft {
|
||||
padding-bottom: @spacing-xs;
|
||||
}
|
||||
}
|
||||
602
src/assets/css/mobile_responsive.less
Normal file
602
src/assets/css/mobile_responsive.less
Normal file
@@ -0,0 +1,602 @@
|
||||
// 移动端响应式适配样式 - LESS版本
|
||||
@import './variables.less';
|
||||
|
||||
// ===== 移动端断点变量 =====
|
||||
// 使用全局变量文件中的断点
|
||||
|
||||
// ===== 移动端断点 =====
|
||||
@media (max-width: @mobile-breakpoint) {
|
||||
// 头部导航移动端适配
|
||||
.header {
|
||||
padding: 10px 0;
|
||||
|
||||
.content {
|
||||
padding: 0 15px;
|
||||
}
|
||||
}
|
||||
|
||||
// 桌面端导航隐藏
|
||||
.desktop {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 移动端导航显示
|
||||
.mobile {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
// 移动端导航样式
|
||||
.mobile-nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logoCell {
|
||||
.logo {
|
||||
height: 40px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.mobileIconsCell {
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端菜单样式
|
||||
.headerMobileMenu {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
overflow-y: auto;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.menuContent {
|
||||
padding: 80px 20px 20px;
|
||||
color: white;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 15px 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 18px;
|
||||
display: block;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.hasSubmenu {
|
||||
color: #3498db;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.subMenu {
|
||||
margin-left: 20px;
|
||||
margin-top: 10px;
|
||||
|
||||
li {
|
||||
border-bottom: none;
|
||||
margin: 10px 0;
|
||||
padding-bottom: 5px;
|
||||
|
||||
a {
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.closeMenu {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
|
||||
&:hover {
|
||||
color: #3498db;
|
||||
}
|
||||
}
|
||||
|
||||
.goBack {
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 2px solid rgba(255, 255, 255, 0.3);
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 16px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
&:hover {
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端横幅适配
|
||||
.banner {
|
||||
height: 60vh;
|
||||
min-height: 400px;
|
||||
|
||||
.banner-content {
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
|
||||
.banner-title {
|
||||
font-size: 2.5rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.banner-button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端内容区域适配
|
||||
.pageWidth {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 40px 0;
|
||||
|
||||
.section-title {
|
||||
font-size: 2rem;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端网格布局适配
|
||||
.grid,
|
||||
.advantages-grid,
|
||||
.areas-grid,
|
||||
.services-grid,
|
||||
.team-grid,
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
// 移动端卡片适配
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-card,
|
||||
.team-card,
|
||||
.contact-card {
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.card-title {
|
||||
font-size: 1.3rem;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端按钮适配
|
||||
.btn,
|
||||
.button {
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
min-height: 44px; // 触摸友好尺寸
|
||||
|
||||
&.btn-large {
|
||||
padding: 15px 30px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
&.btn-small {
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端表单适配
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
font-size: 16px; // 防止iOS缩放
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
min-height: 44px; // 触摸友好尺寸
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #3498db;
|
||||
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 100px;
|
||||
resize: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端图片适配
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// 移动端图标适配
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
&.icon-large {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.icon-small {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端间距适配
|
||||
.mt-mobile { margin-top: 20px !important; }
|
||||
.mb-mobile { margin-bottom: 20px !important; }
|
||||
.ml-mobile { margin-left: 15px !important; }
|
||||
.mr-mobile { margin-right: 15px !important; }
|
||||
|
||||
.pt-mobile { padding-top: 20px !important; }
|
||||
.pb-mobile { padding-bottom: 20px !important; }
|
||||
.pl-mobile { padding-left: 15px !important; }
|
||||
.pr-mobile { padding-right: 15px !important; }
|
||||
|
||||
// 移动端隐藏元素
|
||||
.hide-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
// 移动端显示元素
|
||||
.show-mobile {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
// 移动端文本对齐
|
||||
.text-center-mobile {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.text-left-mobile {
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.text-right-mobile {
|
||||
text-align: right !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 平板端适配 =====
|
||||
@media (min-width: @mobile-breakpoint + 1) and (max-width: @tablet-breakpoint) {
|
||||
.pageWidth {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
.grid,
|
||||
.advantages-grid,
|
||||
.areas-grid,
|
||||
.services-grid,
|
||||
.team-grid,
|
||||
.contact-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 50px 0;
|
||||
}
|
||||
|
||||
.banner {
|
||||
height: 70vh;
|
||||
|
||||
.banner-content {
|
||||
padding: 60px 40px;
|
||||
|
||||
.banner-title {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 小屏幕移动端适配 =====
|
||||
@media (max-width: @small-mobile) {
|
||||
.pageWidth {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
.banner-content {
|
||||
padding: 30px 15px;
|
||||
|
||||
.banner-title {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 30px 0;
|
||||
|
||||
.section-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-card,
|
||||
.team-card,
|
||||
.contact-card {
|
||||
padding: 15px;
|
||||
|
||||
.card-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.btn,
|
||||
.button {
|
||||
padding: 10px 20px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 超小屏幕移动端适配 =====
|
||||
@media (max-width: @xs-mobile) {
|
||||
.pageWidth {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
.banner-content {
|
||||
padding: 25px 10px;
|
||||
|
||||
.banner-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 25px 0;
|
||||
|
||||
.section-title {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-card,
|
||||
.team-card,
|
||||
.contact-card {
|
||||
padding: 12px;
|
||||
|
||||
.card-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.btn,
|
||||
.button {
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 触摸设备优化 =====
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
// 触摸设备禁用悬停效果
|
||||
.hover-lift:hover,
|
||||
.hover-scale:hover,
|
||||
.hover-glow:hover,
|
||||
.hover-rotate:hover,
|
||||
.hover-bounce:hover {
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
// 触摸设备增加触摸反馈
|
||||
.btn,
|
||||
.button,
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-card,
|
||||
.team-card,
|
||||
.contact-card {
|
||||
-webkit-tap-highlight-color: rgba(52, 152, 219, 0.3);
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
transition: transform 0.1s ease;
|
||||
}
|
||||
}
|
||||
|
||||
// 触摸设备优化菜单项
|
||||
.menuContent {
|
||||
li {
|
||||
a {
|
||||
padding: 15px 0; // 增加触摸区域
|
||||
min-height: 44px; // 触摸友好尺寸
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 高分辨率屏幕适配 =====
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
.logo {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
|
||||
.icon {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 横屏模式适配 =====
|
||||
@media (orientation: landscape) and (max-height: 500px) {
|
||||
.headerMobileMenu {
|
||||
.menuContent {
|
||||
padding: 60px 20px 20px;
|
||||
}
|
||||
|
||||
.closeMenu {
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.banner {
|
||||
height: 100vh;
|
||||
|
||||
.banner-content {
|
||||
padding: 30px 20px;
|
||||
|
||||
.banner-title {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 打印样式 =====
|
||||
@media print {
|
||||
.headerMobileMenu,
|
||||
.mobile-nav,
|
||||
.floating-particles,
|
||||
.scroll-progress-bar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.pageWidth {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 20px 0 !important;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
.card,
|
||||
.advantage-card,
|
||||
.area-card,
|
||||
.service-card,
|
||||
.team-card,
|
||||
.contact-card {
|
||||
page-break-inside: avoid;
|
||||
margin-bottom: 15px !important;
|
||||
}
|
||||
}
|
||||
279
src/assets/css/variables.less
Normal file
279
src/assets/css/variables.less
Normal file
@@ -0,0 +1,279 @@
|
||||
// ===== LESS 变量定义文件 =====
|
||||
|
||||
// ===== 颜色变量 =====
|
||||
@primary-color: #3498db;
|
||||
@primary-light: #5dade2;
|
||||
@primary-dark: #2980b9;
|
||||
@primary-lighter: #ebf3fd;
|
||||
|
||||
@success-color: #52c41a;
|
||||
@success-light: #73d13d;
|
||||
@success-dark: #389e0d;
|
||||
@success-lighter: #f6ffed;
|
||||
|
||||
@warning-color: #faad14;
|
||||
@warning-light: #ffc53d;
|
||||
@warning-dark: #d48806;
|
||||
@warning-lighter: #fffbe6;
|
||||
|
||||
@error-color: #f5222d;
|
||||
@error-light: #ff4d4f;
|
||||
@error-dark: #cf1322;
|
||||
@error-lighter: #fff2f0;
|
||||
|
||||
@info-color: #1890ff;
|
||||
@info-light: #40a9ff;
|
||||
@info-dark: #096dd9;
|
||||
@info-lighter: #e6f7ff;
|
||||
|
||||
// 中性色
|
||||
@white: #ffffff;
|
||||
@black: #000000;
|
||||
@gray-1: #fafafa;
|
||||
@gray-2: #f5f5f5;
|
||||
@gray-3: #f0f0f0;
|
||||
@gray-4: #d9d9d9;
|
||||
@gray-5: #bfbfbf;
|
||||
@gray-6: #8c8c8c;
|
||||
@gray-7: #595959;
|
||||
@gray-8: #434343;
|
||||
@gray-9: #262626;
|
||||
@gray-10: #1f1f1f;
|
||||
|
||||
// 文字颜色
|
||||
@text-color: @gray-8;
|
||||
@text-color-secondary: @gray-6;
|
||||
@text-color-disabled: @gray-5;
|
||||
@heading-color: @gray-9;
|
||||
@link-color: @primary-color;
|
||||
@link-hover-color: @primary-light;
|
||||
|
||||
// 背景颜色
|
||||
@bg-color: @white;
|
||||
@bg-color-light: @gray-1;
|
||||
@bg-color-dark: @gray-2;
|
||||
|
||||
// 边框颜色
|
||||
@border-color: @gray-4;
|
||||
@border-color-light: @gray-3;
|
||||
@border-color-dark: @gray-5;
|
||||
|
||||
// ===== 字体变量 =====
|
||||
@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
@font-family-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
|
||||
|
||||
@font-size-base: 14px;
|
||||
@font-size-lg: 16px;
|
||||
@font-size-sm: 12px;
|
||||
@font-size-xs: 10px;
|
||||
|
||||
@font-size-h1: 38px;
|
||||
@font-size-h2: 30px;
|
||||
@font-size-h3: 24px;
|
||||
@font-size-h4: 20px;
|
||||
@font-size-h5: 16px;
|
||||
@font-size-h6: 14px;
|
||||
|
||||
@line-height-base: 1.5715;
|
||||
@line-height-lg: 1.5;
|
||||
@line-height-sm: 1.4;
|
||||
@line-height-xs: 1.3;
|
||||
|
||||
@font-weight-light: 300;
|
||||
@font-weight-normal: 400;
|
||||
@font-weight-medium: 500;
|
||||
@font-weight-semibold: 600;
|
||||
@font-weight-bold: 700;
|
||||
@font-weight-extrabold: 800;
|
||||
|
||||
// ===== 间距变量 =====
|
||||
@spacing-xs: 4px;
|
||||
@spacing-sm: 8px;
|
||||
@spacing-md: 16px;
|
||||
@spacing-lg: 24px;
|
||||
@spacing-xl: 32px;
|
||||
@spacing-xxl: 48px;
|
||||
@spacing-xxxl: 64px;
|
||||
|
||||
@padding-xs: @spacing-xs;
|
||||
@padding-sm: @spacing-sm;
|
||||
@padding-md: @spacing-md;
|
||||
@padding-lg: @spacing-lg;
|
||||
@padding-xl: @spacing-xl;
|
||||
|
||||
@margin-xs: @spacing-xs;
|
||||
@margin-sm: @spacing-sm;
|
||||
@margin-md: @spacing-md;
|
||||
@margin-lg: @spacing-lg;
|
||||
@margin-xl: @spacing-xl;
|
||||
|
||||
// ===== 尺寸变量 =====
|
||||
@border-radius-base: 4px;
|
||||
@border-radius-sm: 2px;
|
||||
@border-radius-lg: 8px;
|
||||
@border-radius-xl: 12px;
|
||||
@border-radius-circle: 50%;
|
||||
|
||||
@border-width-base: 1px;
|
||||
@border-width-thick: 2px;
|
||||
@border-width-thin: 0.5px;
|
||||
|
||||
// ===== 阴影变量 =====
|
||||
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
@box-shadow-sm: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||
@box-shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.2);
|
||||
@box-shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.25);
|
||||
|
||||
@text-shadow-base: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
@text-shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
|
||||
// ===== 断点变量 =====
|
||||
@screen-xs: 480px;
|
||||
@screen-sm: 576px;
|
||||
@screen-md: 768px;
|
||||
@screen-lg: 992px;
|
||||
@screen-xl: 1200px;
|
||||
@screen-xxl: 1600px;
|
||||
|
||||
@mobile-breakpoint: @screen-md;
|
||||
@tablet-breakpoint: @screen-lg;
|
||||
@desktop-breakpoint: @screen-xl;
|
||||
|
||||
// 移动端断点变量
|
||||
@small-mobile: 480px;
|
||||
@xs-mobile: 360px;
|
||||
|
||||
// ===== 动画变量 =====
|
||||
@animation-duration-base: 0.2s;
|
||||
@animation-duration-fast: 0.1s;
|
||||
@animation-duration-slow: 0.3s;
|
||||
@animation-duration-slower: 0.5s;
|
||||
|
||||
@animation-timing-base: ease;
|
||||
@animation-timing-ease-in: ease-in;
|
||||
@animation-timing-ease-out: ease-out;
|
||||
@animation-timing-ease-in-out: ease-in-out;
|
||||
@animation-timing-linear: linear;
|
||||
|
||||
@animation-delay-base: 0s;
|
||||
@animation-delay-fast: 0.1s;
|
||||
@animation-delay-slow: 0.3s;
|
||||
|
||||
// ===== Z-index 变量 =====
|
||||
@zindex-dropdown: 1000;
|
||||
@zindex-sticky: 1020;
|
||||
@zindex-fixed: 1030;
|
||||
@zindex-modal-backdrop: 1040;
|
||||
@zindex-modal: 1050;
|
||||
@zindex-popover: 1060;
|
||||
@zindex-tooltip: 1070;
|
||||
@zindex-toast: 1080;
|
||||
|
||||
// ===== 组件特定变量 =====
|
||||
|
||||
// 按钮
|
||||
@btn-height-base: 32px;
|
||||
@btn-height-lg: 40px;
|
||||
@btn-height-sm: 24px;
|
||||
@btn-padding-horizontal-base: @padding-md;
|
||||
@btn-padding-horizontal-lg: @padding-lg;
|
||||
@btn-padding-horizontal-sm: @padding-sm;
|
||||
|
||||
// 输入框
|
||||
@input-height-base: 32px;
|
||||
@input-height-lg: 40px;
|
||||
@input-height-sm: 24px;
|
||||
@input-padding-horizontal: @padding-sm;
|
||||
|
||||
// 卡片
|
||||
@card-padding-base: @padding-lg;
|
||||
@card-padding-sm: @padding-md;
|
||||
@card-padding-lg: @padding-xl;
|
||||
|
||||
// 表格
|
||||
@table-padding-vertical: @padding-sm;
|
||||
@table-padding-horizontal: @padding-md;
|
||||
|
||||
// 分页
|
||||
@pagination-item-size: 32px;
|
||||
@pagination-item-size-sm: 24px;
|
||||
|
||||
// 标签
|
||||
@tag-height: 20px;
|
||||
@tag-height-lg: 28px;
|
||||
@tag-height-sm: 16px;
|
||||
|
||||
// 徽章
|
||||
@badge-height: 20px;
|
||||
@badge-height-sm: 14px;
|
||||
@badge-height-lg: 24px;
|
||||
|
||||
// ===== 工具函数 =====
|
||||
|
||||
// 颜色混合函数
|
||||
.lighten(@color, @amount) {
|
||||
color: lighten(@color, @amount);
|
||||
}
|
||||
|
||||
.darken(@color, @amount) {
|
||||
color: darken(@color, @amount);
|
||||
}
|
||||
|
||||
// 透明度函数
|
||||
.alpha(@color, @opacity) {
|
||||
color: fade(@color, @opacity);
|
||||
}
|
||||
|
||||
// 响应式混合
|
||||
.mobile(@rules) {
|
||||
@media (max-width: @mobile-breakpoint) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
.tablet(@rules) {
|
||||
@media (min-width: @mobile-breakpoint + 1) and (max-width: @tablet-breakpoint) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
.desktop(@rules) {
|
||||
@media (min-width: @tablet-breakpoint + 1) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
// 触摸设备检测
|
||||
.touch-device(@rules) {
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
// 高分辨率屏幕
|
||||
.high-dpi(@rules) {
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
// 打印样式
|
||||
.print(@rules) {
|
||||
@media print {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
// 横屏模式
|
||||
.landscape(@rules) {
|
||||
@media (orientation: landscape) and (max-height: 500px) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
// 减少动画偏好
|
||||
.reduced-motion(@rules) {
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
@@ -116,6 +116,7 @@ export default {
|
||||
mounted() {
|
||||
this.initHeader()
|
||||
this.initScrollListener()
|
||||
this.initMobileMenu()
|
||||
},
|
||||
methods: {
|
||||
// 封装事件监听器创建,提高代码复用性
|
||||
@@ -197,6 +198,52 @@ export default {
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 初始化移动端菜单
|
||||
initMobileMenu() {
|
||||
// 汉堡菜单点击事件
|
||||
this.add_event_listener("hamburger", "click", () => {
|
||||
this.toggle_class("mobileMenu", "active", true);
|
||||
}, true);
|
||||
|
||||
// 返回按钮点击事件
|
||||
this.add_event_listener(".linkGoBack", "click", () => {
|
||||
this.remove_class("mobileMenu", "active", true);
|
||||
// 关闭移动端菜单后滚动到顶部
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
});
|
||||
|
||||
// 点击菜单项后自动关闭菜单
|
||||
const menuLinks = document.querySelectorAll('.headerMobileMenu a');
|
||||
menuLinks.forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
this.remove_class("mobileMenu", "active", true);
|
||||
});
|
||||
});
|
||||
|
||||
// 点击菜单外部区域关闭菜单
|
||||
document.addEventListener('click', (e) => {
|
||||
const mobileMenu = document.getElementById('mobileMenu');
|
||||
const hamburger = document.getElementById('hamburger');
|
||||
|
||||
if (mobileMenu && mobileMenu.classList.contains('active') &&
|
||||
!mobileMenu.contains(e.target) &&
|
||||
!hamburger.contains(e.target)) {
|
||||
this.remove_class("mobileMenu", "active", true);
|
||||
}
|
||||
});
|
||||
|
||||
// ESC键关闭菜单
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
this.remove_class("mobileMenu", "active", true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import './assets/css/cookieconsent.min.css'
|
||||
import './assets/css/common.css'
|
||||
import './assets/css/animations.css'
|
||||
import './assets/css/common.less'
|
||||
import './assets/css/content_pages.less'
|
||||
import './assets/css/animations.less'
|
||||
import './assets/css/mobile_responsive.less'
|
||||
import './assets/css/common_mobile.less'
|
||||
import 'swiper/css/swiper.min.css'
|
||||
import 'es6-promise/auto'
|
||||
import './static/animation_helper'
|
||||
import './static/scroll_helper'
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
250
src/static/scroll_helper.js
Normal file
250
src/static/scroll_helper.js
Normal file
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* 滚动控制助手 - 处理页面刷新和路由切换时的滚动行为
|
||||
*/
|
||||
class ScrollHelper {
|
||||
constructor() {
|
||||
this.isInitialized = false;
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化滚动助手
|
||||
*/
|
||||
init() {
|
||||
if (this.isInitialized) return;
|
||||
|
||||
// 监听页面加载完成事件
|
||||
this.handlePageLoad();
|
||||
|
||||
// 监听路由变化事件
|
||||
this.handleRouteChange();
|
||||
|
||||
// 监听页面刷新事件
|
||||
this.handlePageRefresh();
|
||||
|
||||
// 监听浏览器前进后退事件
|
||||
this.handleBrowserNavigation();
|
||||
|
||||
this.isInitialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理页面加载完成
|
||||
*/
|
||||
handlePageLoad() {
|
||||
// 页面完全加载后滚动到顶部
|
||||
if (document.readyState === 'complete') {
|
||||
this.scrollToTop();
|
||||
} else {
|
||||
window.addEventListener('load', () => {
|
||||
this.scrollToTop();
|
||||
});
|
||||
}
|
||||
|
||||
// DOM内容加载完成后也滚动到顶部
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
this.scrollToTop();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理路由变化
|
||||
*/
|
||||
handleRouteChange() {
|
||||
// 监听 Vue Router 的全局前置守卫
|
||||
if (window.Vue && window.Vue.prototype.$router) {
|
||||
window.Vue.prototype.$router.beforeEach((to, from, next) => {
|
||||
// 路由切换时滚动到顶部
|
||||
this.scrollToTop();
|
||||
next();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理页面刷新
|
||||
*/
|
||||
handlePageRefresh() {
|
||||
// 监听页面即将刷新事件
|
||||
window.addEventListener('beforeunload', () => {
|
||||
// 保存当前滚动位置到 sessionStorage
|
||||
sessionStorage.setItem('scrollPosition', window.pageYOffset);
|
||||
});
|
||||
|
||||
// 页面加载完成后检查是否需要滚动到顶部
|
||||
window.addEventListener('load', () => {
|
||||
const savedPosition = sessionStorage.getItem('scrollPosition');
|
||||
if (savedPosition) {
|
||||
// 清除保存的位置
|
||||
sessionStorage.removeItem('scrollPosition');
|
||||
// 滚动到顶部
|
||||
this.scrollToTop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理浏览器前进后退
|
||||
*/
|
||||
handleBrowserNavigation() {
|
||||
// 监听 popstate 事件(浏览器前进后退)
|
||||
window.addEventListener('popstate', () => {
|
||||
// 延迟执行,确保路由更新完成
|
||||
setTimeout(() => {
|
||||
this.scrollToTop();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动到页面顶部
|
||||
*/
|
||||
scrollToTop(options = {}) {
|
||||
const defaultOptions = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth'
|
||||
};
|
||||
|
||||
const config = { ...defaultOptions, ...options };
|
||||
|
||||
// 检查浏览器是否支持平滑滚动
|
||||
if (!this.supportsSmoothScrolling()) {
|
||||
config.behavior = 'auto';
|
||||
}
|
||||
|
||||
// 执行滚动
|
||||
window.scrollTo(config);
|
||||
|
||||
// 同时滚动 body 和 html 元素(兼容性处理)
|
||||
if (document.body) {
|
||||
document.body.scrollTop = 0;
|
||||
document.body.scrollLeft = 0;
|
||||
}
|
||||
if (document.documentElement) {
|
||||
document.documentElement.scrollTop = 0;
|
||||
document.documentElement.scrollLeft = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动到指定元素
|
||||
*/
|
||||
scrollToElement(selector, options = {}) {
|
||||
const element = document.querySelector(selector);
|
||||
if (!element) return;
|
||||
|
||||
const defaultOptions = {
|
||||
behavior: 'smooth',
|
||||
block: 'start',
|
||||
inline: 'nearest'
|
||||
};
|
||||
|
||||
const config = { ...defaultOptions, ...options };
|
||||
|
||||
// 检查浏览器是否支持 scrollIntoView
|
||||
if (element.scrollIntoView) {
|
||||
element.scrollIntoView(config);
|
||||
} else {
|
||||
// 降级处理:计算元素位置并滚动
|
||||
const rect = element.getBoundingClientRect();
|
||||
const scrollTop = window.pageYOffset + rect.top;
|
||||
this.scrollToTop({ top: scrollTop, behavior: config.behavior });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查浏览器是否支持平滑滚动
|
||||
*/
|
||||
supportsSmoothScrolling() {
|
||||
return 'scrollBehavior' in document.documentElement.style;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前滚动位置
|
||||
*/
|
||||
getScrollPosition() {
|
||||
return {
|
||||
x: window.pageXOffset || document.documentElement.scrollLeft,
|
||||
y: window.pageYOffset || document.documentElement.scrollTop
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置滚动位置
|
||||
*/
|
||||
setScrollPosition(x, y, behavior = 'smooth') {
|
||||
const options = {
|
||||
top: y,
|
||||
left: x,
|
||||
behavior: this.supportsSmoothScrolling() ? behavior : 'auto'
|
||||
};
|
||||
|
||||
window.scrollTo(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动到底部
|
||||
*/
|
||||
scrollToBottom(behavior = 'smooth') {
|
||||
const scrollHeight = Math.max(
|
||||
document.body.scrollHeight,
|
||||
document.documentElement.scrollHeight,
|
||||
document.body.offsetHeight,
|
||||
document.documentElement.offsetHeight,
|
||||
document.body.clientHeight,
|
||||
document.documentElement.clientHeight
|
||||
);
|
||||
|
||||
this.scrollToTop({
|
||||
top: scrollHeight,
|
||||
behavior: behavior
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动到指定百分比位置
|
||||
*/
|
||||
scrollToPercentage(percentage, behavior = 'smooth') {
|
||||
const scrollHeight = Math.max(
|
||||
document.body.scrollHeight,
|
||||
document.documentElement.scrollHeight
|
||||
);
|
||||
const targetPosition = (scrollHeight - window.innerHeight) * (percentage / 100);
|
||||
|
||||
this.scrollToTop({
|
||||
top: targetPosition,
|
||||
behavior: behavior
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听滚动事件
|
||||
*/
|
||||
onScroll(callback) {
|
||||
window.addEventListener('scroll', callback, { passive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除滚动监听器
|
||||
*/
|
||||
offScroll(callback) {
|
||||
window.removeEventListener('scroll', callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁滚动助手
|
||||
*/
|
||||
destroy() {
|
||||
// 清理事件监听器
|
||||
this.isInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局实例
|
||||
window.scrollHelper = new ScrollHelper();
|
||||
|
||||
// 导出类(如果使用模块系统)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = ScrollHelper;
|
||||
}
|
||||
@@ -7,13 +7,27 @@
|
||||
|
||||
<!-- 现代化横幅区域 -->
|
||||
<div class="banner" data-parallax="0.3">
|
||||
<!-- 浮动粒子背景 -->
|
||||
<div class="floating-particles">
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
<div class="floating-particle"></div>
|
||||
</div>
|
||||
|
||||
<swiper ref="swiper" :options="swiperOption">
|
||||
<swiper-slide v-for="banner in banners" :key="banner.img">
|
||||
<div class="banner-content">
|
||||
<img :src="banner.img" width="100%" />
|
||||
<div class="banner-overlay">
|
||||
<div class="banner-text">
|
||||
<h1 class="banner-title animate fade-in-down">{{banner.title}}</h1>
|
||||
<h1 class="banner-title animate fade-in-down text-glow">{{banner.title}}</h1>
|
||||
<p class="banner-subtitle animate fade-in-up delay-1s">{{banner.subtitle}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -88,6 +88,27 @@ module.exports = {
|
||||
})
|
||||
]
|
||||
}
|
||||
},
|
||||
// LESS 配置
|
||||
less: {
|
||||
lessOptions: {
|
||||
javascriptEnabled: true,
|
||||
modifyVars: {
|
||||
// 可以在这里定义全局LESS变量
|
||||
'@primary-color': '#3498db',
|
||||
'@success-color': '#52c41a',
|
||||
'@warning-color': '#faad14',
|
||||
'@error-color': '#f5222d',
|
||||
'@font-size-base': '14px',
|
||||
'@heading-color': '#262626',
|
||||
'@text-color': '#595959',
|
||||
'@text-color-secondary': '#8c8c8c',
|
||||
'@disabled-color': '#bfbfbf',
|
||||
'@border-radius-base': '4px',
|
||||
'@border-color-base': '#d9d9d9',
|
||||
'@box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
99
yarn.lock
99
yarn.lock
@@ -795,7 +795,7 @@
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/json-schema@^7.0.5":
|
||||
"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8":
|
||||
version "7.0.15"
|
||||
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
@@ -1254,7 +1254,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
|
||||
resolved "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
|
||||
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
|
||||
|
||||
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
|
||||
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||
@@ -2495,6 +2495,13 @@ cookie@0.7.1:
|
||||
resolved "https://registry.npmmirror.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
|
||||
integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
|
||||
|
||||
copy-anything@^2.0.1:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
|
||||
integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==
|
||||
dependencies:
|
||||
is-what "^3.14.1"
|
||||
|
||||
copy-concurrently@^1.0.0:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmmirror.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
|
||||
@@ -3381,7 +3388,7 @@ entities@^2.0.0:
|
||||
resolved "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
|
||||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||
|
||||
errno@^0.1.3, errno@~0.1.7:
|
||||
errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
|
||||
integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
|
||||
@@ -4754,6 +4761,13 @@ iconv-lite@0.4.24:
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
|
||||
iconv-lite@^0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
icss-replace-symbols@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmmirror.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
|
||||
@@ -4791,6 +4805,11 @@ ignore@^5.1.1:
|
||||
resolved "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
|
||||
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
|
||||
|
||||
image-size@~0.5.0:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
|
||||
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
|
||||
|
||||
image-webpack-loader@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.npmmirror.com/image-webpack-loader/-/image-webpack-loader-8.1.0.tgz#cd97172e1e7304ef5eb898344fc25bbb650fc7d7"
|
||||
@@ -5415,6 +5434,11 @@ is-weakset@^2.0.3:
|
||||
call-bound "^1.0.3"
|
||||
get-intrinsic "^1.2.6"
|
||||
|
||||
is-what@^3.14.1:
|
||||
version "3.14.1"
|
||||
resolved "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
|
||||
integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
|
||||
|
||||
is-windows@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||
@@ -5627,6 +5651,11 @@ kind-of@^6.0.2:
|
||||
resolved "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
|
||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||
|
||||
klona@^2.0.4:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
|
||||
integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==
|
||||
|
||||
launch-editor-middleware@^2.2.1:
|
||||
version "2.11.1"
|
||||
resolved "https://registry.npmmirror.com/launch-editor-middleware/-/launch-editor-middleware-2.11.1.tgz#8042f841b7f6cf2d7aafd5e0824e49ab356a5bb1"
|
||||
@@ -5642,6 +5671,32 @@ launch-editor@^2.11.1, launch-editor@^2.2.1:
|
||||
picocolors "^1.1.1"
|
||||
shell-quote "^1.8.3"
|
||||
|
||||
less-loader@7.3.0:
|
||||
version "7.3.0"
|
||||
resolved "https://registry.npmmirror.com/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5"
|
||||
integrity sha512-Mi8915g7NMaLlgi77mgTTQvK022xKRQBIVDSyfl3ErTuBhmZBQab0mjeJjNNqGbdR+qrfTleKXqbGI4uEFavxg==
|
||||
dependencies:
|
||||
klona "^2.0.4"
|
||||
loader-utils "^2.0.0"
|
||||
schema-utils "^3.0.0"
|
||||
|
||||
less@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.npmmirror.com/less/-/less-4.4.1.tgz#2f97168bf887ca6a9957ee69e16cc34f8b007cc7"
|
||||
integrity sha512-X9HKyiXPi0f/ed0XhgUlBeFfxrlDP3xR4M7768Zl+WXLUViuL9AOPPJP4nCV0tgRWvTYvpNmN0SFhZOQzy16PA==
|
||||
dependencies:
|
||||
copy-anything "^2.0.1"
|
||||
parse-node-version "^1.0.1"
|
||||
tslib "^2.3.0"
|
||||
optionalDependencies:
|
||||
errno "^0.1.1"
|
||||
graceful-fs "^4.1.2"
|
||||
image-size "~0.5.0"
|
||||
make-dir "^2.1.0"
|
||||
mime "^1.4.1"
|
||||
needle "^3.1.0"
|
||||
source-map "~0.6.0"
|
||||
|
||||
lines-and-columns@^1.1.6:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
@@ -5799,7 +5854,7 @@ make-dir@^1.0.0, make-dir@^1.2.0:
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
make-dir@^2.0.0:
|
||||
make-dir@^2.0.0, make-dir@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
|
||||
integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
|
||||
@@ -5950,7 +6005,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24,
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime@1.6.0:
|
||||
mime@1.6.0, mime@^1.4.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
@@ -6140,6 +6195,14 @@ nanomatch@^1.2.9:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
needle@^3.1.0:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz#63f75aec580c2e77e209f3f324e2cdf3d29bd049"
|
||||
integrity sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==
|
||||
dependencies:
|
||||
iconv-lite "^0.6.3"
|
||||
sax "^1.2.4"
|
||||
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
|
||||
@@ -6676,6 +6739,11 @@ parse-json@^5.0.0:
|
||||
json-parse-even-better-errors "^2.3.0"
|
||||
lines-and-columns "^1.1.6"
|
||||
|
||||
parse-node-version@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
|
||||
integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
|
||||
|
||||
parse5-htmlparser2-tree-adapter@^6.0.0:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
|
||||
@@ -7802,11 +7870,16 @@ safe-regex@^1.1.0:
|
||||
dependencies:
|
||||
ret "~0.1.10"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sax@^1.2.4:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
|
||||
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
|
||||
|
||||
sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.npmmirror.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
@@ -7830,6 +7903,15 @@ schema-utils@^2.6.5, schema-utils@^2.7.1:
|
||||
ajv "^6.12.4"
|
||||
ajv-keywords "^3.5.2"
|
||||
|
||||
schema-utils@^3.0.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
|
||||
integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.8"
|
||||
ajv "^6.12.5"
|
||||
ajv-keywords "^3.5.2"
|
||||
|
||||
seek-bzip@^1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmmirror.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4"
|
||||
@@ -8801,6 +8883,11 @@ tryer@^1.0.1:
|
||||
resolved "https://registry.npmmirror.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
|
||||
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
|
||||
|
||||
tslib@^2.3.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
tty-browserify@0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
|
||||
|
||||
Reference in New Issue
Block a user