下面是一套完整的SCSS全局方法,专门为大屏适配和高效开发设计:
全局SCSS工具文件(styles/_mixins.scss)
// =============================================
// 变量定义
// =============================================
// 设计稿基准尺寸
$design-width: 1920px !default;
$design-height: 1080px !default;
// 断点设置
$breakpoints: (
'xs': 0,
'sm': 576px,
'md': 768px,
'lg': 992px,
'xl': 1200px,
'xxl': 1400px,
'4k': 2560px,
'8k': 3840px
) !default;
// 颜色系统
$colors: (
'primary': #1890ff,
'success': #52c41a,
'warning': #faad14,
'error': #f5222d,
'info': #13c2c2,
'white': #ffffff,
'black': #000000,
'transparent': transparent
) !default;
// 字体大小阶梯
$font-sizes: (
'xs': 12px,
'sm': 14px,
'base': 16px,
'lg': 18px,
'xl': 20px,
'2xl': 24px,
'3xl': 30px,
'4xl': 36px,
'5xl': 48px,
'6xl': 60px
) !default;
// 间距系统
$spacing: (
'0': 0,
'1': 4px,
'2': 8px,
'3': 12px,
'4': 16px,
'5': 20px,
'6': 24px,
'8': 32px,
'10': 40px,
'12': 48px,
'16': 64px,
'20': 80px,
'24': 96px,
'32': 128px
) !default;
// =============================================
// 响应式工具
// =============================================
// 媒体查询混合
@mixin respond-to($breakpoint) {
@if map-has-key($breakpoints, $breakpoint) {
$value: map-get($breakpoints, $breakpoint);
@if $value == 0 {
@content;
} @else {
@media screen and (min-width: $value) {
@content;
}
}
} @else {
@warn "未知的断点: `#{$breakpoint}`. 可用的断点: #{map-keys($breakpoints)}";
}
}
// 高DPI屏幕适配
@mixin retina {
@media only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (min--moz-device-pixel-ratio: 2),
only screen and (-o-min-device-pixel-ratio: 2/1),
only screen and (min-device-pixel-ratio: 2),
only screen and (min-resolution: 192dpi),
only screen and (min-resolution: 2dppx) {
@content;
}
}
// 横屏/竖屏检测
@mixin landscape {
@media (orientation: landscape) {
@content;
}
}
@mixin portrait {
@media (orientation: portrait) {
@content;
}
}
// =============================================
// 大屏适配核心方法
// =============================================
// 根据设计稿尺寸计算vw/vh
@function vw($px) {
@return math.div($px, $design-width) * 100vw;
}
@function vh($px) {
@return math.div($px, $design-height) * 100vh;
}
// 字体大小适配(支持最小最大限制)
@mixin responsive-font($min-size, $max-size, $min-width: 1200px, $max-width: 3840px) {
font-size: #{$min-size}px;
@media (min-width: #{$min-width}) and (max-width: #{$max-width}) {
font-size: calc(
#{$min-size}px + (#{$max-size} - #{$min-size}) *
((100vw - #{$min-width}) / (#{$max-width} - #{$min-width}))
);
}
@media (min-width: #{$max-width}) {
font-size: #{$max-size}px;
}
}
// 元素尺寸适配
@mixin responsive-size($property, $min-value, $max-value, $min-width: 1200px, $max-width: 3840px) {
#{$property}: #{$min-value}px;
@media (min-width: #{$min-width}) and (max-width: #{$max-width}) {
#{$property}: calc(
#{$min-value}px + (#{$max-value} - #{$min-value}) *
((100vw - #{$min-width}) / (#{$max-width} - #{$min-width}))
);
}
@media (min-width: #{$max-width}) {
#{$property}: #{$max-value}px;
}
}
// =============================================
// 颜色工具
// =============================================
// 获取颜色
@function color($key) {
@if map-has-key($colors, $key) {
@return map-get($colors, $key);
}
@warn "未知的颜色 `#{$key}`";
@return null;
}
// 颜色透明度调整
@function color-alpha($color, $opacity) {
@if type-of($color) == 'color' {
@return rgba($color, $opacity);
}
@return unquote("rgba(var(--#{$color}), #{$opacity})");
}
// 颜色变亮/变暗
@function color-lighten($color, $amount) {
@return lighten($color, $amount);
}
@function color-darken($color, $amount) {
@return darken($color, $amount);
}
// 渐变生成器
@mixin gradient-linear($direction: to bottom, $colors...) {
background: linear-gradient($direction, $colors);
}
@mixin gradient-radial($shape: circle, $colors...) {
background: radial-gradient($shape, $colors);
}
// =============================================
// 字体工具
// =============================================
// 字体大小获取
@function font-size($key) {
@if map-has-key($font-sizes, $key) {
@return map-get($font-sizes, $key);
}
@warn "未知的字体大小 `#{$key}`";
@return null;
}
// 字体族设置
@mixin font-family($family: sans-serif) {
font-family: $family;
}
// 文字溢出省略号
@mixin text-ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@mixin text-ellipsis-multi($lines: 2) {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
// =============================================
// 布局工具
// =============================================
// 间距工具
@function spacing($key) {
@if map-has-key($spacing, $key) {
@return map-get($spacing, $key);
}
@warn "未知的间距 `#{$key}`";
@return null;
}
// Flexbox 布局
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin flex-between {
display: flex;
justify-content: space-between;
align-items: center;
}
@mixin flex-column {
display: flex;
flex-direction: column;
}
// 绝对定位居中
@mixin absolute-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@mixin absolute-vertical {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
@mixin absolute-horizontal {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
// 尺寸设置
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
@mixin square($size) {
@include size($size);
}
@mixin circle($size) {
@include size($size);
border-radius: 50%;
}
// =============================================
// 视觉效果工具
// =============================================
// 边框阴影
@mixin shadow($level: 1) {
@if $level == 1 {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
} @else if $level == 2 {
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
} @else if $level == 3 {
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
} @else if $level == 4 {
box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
} @else if $level == 5 {
box-shadow: 0 19px 38px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);
}
}
// 玻璃拟态效果
@mixin glassmorphism($blur: 10px, $opacity: 0.1) {
background: rgba(255, 255, 255, $opacity);
backdrop-filter: blur($blur);
border: 1px solid rgba(255, 255, 255, 0.2);
}
// 边框渐变
@mixin border-gradient($direction, $colors, $width: 2px) {
border: $width solid transparent;
background: linear-gradient(white, white) padding-box,
linear-gradient($direction, $colors) border-box;
}
// 动画混合
@mixin transition($properties: all, $duration: 0.3s, $easing: ease) {
transition: $properties $duration $easing;
}
@mixin animation($name, $duration: 1s, $timing: ease, $delay: 0s, $iteration: 1, $direction: normal) {
animation: $name $duration $timing $delay $iteration $direction;
}
// =============================================
// 大屏专用样式
// =============================================
// 数据大屏容器
@mixin data-screen-container {
width: 100vw;
height: 100vh;
overflow: hidden;
position: relative;
background: linear-gradient(135deg, #1a2a6c, #2a3a7c, #3a4a8c);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
pointer-events: none;
}
}
// 图表面板样式
@mixin chart-panel {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(32, 255, 255, 0.2);
border-radius: 8px;
backdrop-filter: blur(10px);
.panel-header {
height: 40px;
background: linear-gradient(90deg, rgba(0, 102, 204, 0.5), rgba(0, 204, 255, 0.3));
border-bottom: 1px solid rgba(32, 255, 255, 0.2);
@include flex-between;
padding: 0 15px;
.panel-title {
color: white;
font-size: font-size('lg');
font-weight: bold;
margin: 0;
}
}
}
// 发光效果
@mixin glow-effect($color: #00f2ff, $size: 10px) {
box-shadow: 0 0 $size $color;
}
// 流光动画
@mixin flowing-light($color: rgba(0, 242, 255, 0.5)) {
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
to bottom right,
transparent 0%,
$color 50%,
transparent 100%
);
transform: rotate(30deg);
animation: flowing 3s infinite linear;
}
@keyframes flowing {
0% { transform: translateX(-100%) translateY(-100%) rotate(30deg); }
100% { transform: translateX(100%) translateY(100%) rotate(30deg); }
}
}
// =============================================
// 工具类生成器
// =============================================
// 生成间距工具类
@mixin generate-spacing-utilities {
@each $key, $value in $spacing {
.m-#{$key} { margin: $value; }
.mx-#{$key} { margin-left: $value; margin-right: $value; }
.my-#{$key} { margin-top: $value; margin-bottom: $value; }
.mt-#{$key} { margin-top: $value; }
.mr-#{$key} { margin-right: $value; }
.mb-#{$key} { margin-bottom: $value; }
.ml-#{$key} { margin-left: $value; }
.p-#{$key} { padding: $value; }
.px-#{$key} { padding-left: $value; padding-right: $value; }
.py-#{$key} { padding-top: $value; padding-bottom: $value; }
.pt-#{$key} { padding-top: $value; }
.pr-#{$key} { padding-right: $value; }
.pb-#{$key} { padding-bottom: $value; }
.pl-#{$key} { padding-left: $value; }
}
}
// 生成颜色工具类
@mixin generate-color-utilities {
@each $key, $value in $colors {
.text-#{$key} { color: $value; }
.bg-#{$key} { background-color: $value; }
.border-#{$key} { border-color: $value; }
}
}
主样式文件(styles/main.scss)
// 引入工具库
@use 'mixins' as *;
// 重置样式
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
// 基础样式
html {
font-size: 16px;
line-height: 1.5;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
color: color('white');
background-color: color('black');
}
// 工具类生成
@include generate-spacing-utilities;
@include generate-color-utilities;
// 响应式隐藏/显示
.hidden {
display: none !important;
}
@each $breakpoint in map-keys($breakpoints) {
@if $breakpoint != 'xs' {
@include respond-to($breakpoint) {
.hidden-#{$breakpoint} {
display: none !important;
}
.visible-#{$breakpoint} {
display: block !important;
}
}
}
}
// 大屏专用类
.data-screen {
@include data-screen-container;
}
.chart-panel {
@include chart-panel;
}
.glass-effect {
@include glassmorphism;
}
// 文字工具类
.text-ellipsis {
@include text-ellipsis;
}
.text-center { text-align: center; }
.text-left { text-align: left; }
.text-right { text-align: right; }
// 布局工具类
.flex { display: flex; }
.flex-center { @include flex-center; }
.flex-between { @include flex-between; }
.flex-column { @include flex-column; }
// 自定义滚动条
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
border-radius: 3px;
&:hover {
background: rgba(255, 255, 255, 0.5);
}
}
在Vue项目中使用
1. 配置Vue(vite.config.ts)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/mixins.scss";`
}
}
},
resolve: {
alias: {
'@': '/src'
}
}
})
2. 在组件中使用示例
<template>
<div class="data-screen">
<div class="chart-panel glass-effect m-4 p-6">
<h3 class="text-xl text-primary">销售数据</h3>
<div class="chart-container"></div>
</div>
</div>
</template>
<script setup lang="ts">
// 组件逻辑
</script>
<style lang="scss" scoped>
.data-screen {
// 使用mixin
@include data-screen-container;
.chart-panel {
// 使用函数计算尺寸
width: vw(400);
height: vh(300);
h3 {
// 响应式字体
@include responsive-font(16, 24);
// 发光效果
@include glow-effect(color('primary'), 5px);
}
}
}
// 响应式处理
@include respond-to('4k') {
.chart-panel {
width: vw(600);
height: vh(400);
}
}
@include respond-to('8k') {
.chart-panel {
width: vw(800);
height: vh(500);
}
}
</style>
主要特性说明
1. 大屏适配核心
vw()/vh()函数:基于设计稿的视口单位转换- 响应式字体和尺寸:平滑过渡不同分辨率
- 高DPI屏幕支持:Retina屏优化
2. 开发效率提升
- 统一的颜色、间距、字体系统
- 常用的布局mixin(flex居中、绝对定位等)
- 工具类生成器
3. 视觉效果丰富
- 玻璃拟态效果
- 渐变边框
- 发光和流光动画
4. 维护性强
- 统一的变量管理
- 模块化设计
- 清晰的命名规范
这套SCSS全局方法可以显著提高大屏项目的开发效率,保证样式的一致性和可维护性,同时提供优秀的视觉体验。