背景
以往寫媒體查詢可能是這樣的:
.header {
display: flex;
width: 100%;
}
@media (width >= 320px) and (width <= 480px) {
.header {
height: 50px;
}
}
@media (width > 480px) and (width <= 768px) {
.header {
height: 60px;
}
}
@media (width > 768px) and (width <= 1024px) {
.header {
height: 70px;
}
}
@media (width > 1024px) and (width <= 1200) {
.header {
height: 80px;
}
}
@media (width > 1200) {
.header {
height: 100px;
}
}
以上寫法可以看到寫起來非常不方便,可讀性也很差。因此希望用 sass 優(yōu)化一下寫法。
目標
希望可以這樣寫媒體查詢:
.header {
display: flex;
width: 100%;
手機: {
height: 50px;
}
平板: {
height: 60px;
}
...
}
sass 混合功能
/* 定義混合函數(shù) */
@mixin flexCenter($jus_c: center, $ali_i: center) {
display: flex;
justify-content: $jus_c;
align-items: $ali_i;
}
/* 使用混合函數(shù) */
.header {
width: 100%;
@include flexCenter(space-between, flex-end);
}
sass if判斷和插槽
混合函數(shù)中使用 @if判斷區(qū)分不同設備,@content類似于 vue 插槽接收使用者在方法體中插入的內(nèi)容。
@mixin respond-to($breakpoint) {
@if $breakpoint == mobile {
@media screen and (width <= 767px) {
@content;
}
} @else if $breakpoint == tablet {
@media screen and (width >= 768px) and (width <= 1023px) {
@content;
}
} @else if $breakpoint == desktop {
@media screen and (width >= 1024px) {
@content;
}
} @else if $breakpoint == wide {
@media screen and (width >= 1200px) {
@content;
}
}
}
使用:
.header {
width: 100%;
height: 100vh;
@include respond-to(mobile) {
height: 100px;
}
@include respond-to(tablet) {
height: 200px;
}
...
background-color: rgb(139 133 133);
}
上面代碼已經(jīng)基本達到書寫媒體查詢的目標。但是 if else 太多了,不好看。還可以用策略模式優(yōu)化一下。
進階:sass 定義對象優(yōu)化代碼結構
用 hash 映射優(yōu)化 if,也就是定義一個對象。sass 中可以定義對象。
注意:sass 中()括號就代表 js 的花括號{}和方括號[]。
以下就是一個對象,這 5 個屬性設置 5 個斷點,除最后一個大屏外,其他斷點屬性值為數(shù)組。
之前的代碼設置了 4 個斷點,區(qū)別不大。
/* 定義斷點對象 */
$breakpoints: (
phone: (320px,480px),
pad: (481px,768px),
notebook: (769px,1024px),
desktop: (1025px,1280px),
tv: 1281px
);
sass 讀取對象中的值:
-
map-get(obj, prop):獲取對象的屬性值
sass 判斷數(shù)據(jù)類型:
-
type-of($var)- 數(shù)組類型:list
- 數(shù)值類型:number
@mixin respond-to($breakname) {
/* 1. 讀取斷點對象屬性值 */
$bp: map-get($breakpoints, $breakname);
/* 2. 類型判斷是否為數(shù)組 */
@if type-of($bp) == "list" {
/* 3. 取出數(shù)組中的數(shù)據(jù) */
$min: nth($bp, 1);
$max: nth($bp, 2);
@media screen and (min-width: $min) and (max-width: $max) {
@content;
}
/* 4. tv 大屏 */
} @else if type-of($bp) == "number" {
@media screen and (min-width: $bp) {
@content;
}
} @else {
@warn "`$breakname` is not a valid breakpoint name.";
}
}
vite 配置全局使用
直接在組件中 @include 使用混合函數(shù),可能會報錯:
[vite] Internal server error: [sass] Undefined mixin.
這是因為 minix 需要預編譯,在 vite 中配置:
Vite
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
javascriptEnabled: true,
additionalData: `@use "@/styles/minix.scss" as *;`
}
}
}
});
組件中使用:
.header {
width: 100%;
height: 100vh;
@include respond-to(phone) {
height: 100px;
}
@include respond-to(tv) {
height: 200px;
}
background-color: rgb(139 133 133);
}
完整代碼
$breakpoints: (
phone: (
320px,
480px
),
pad: (
481px,
768px
),
notebook: (
769px,
1024px
),
desktop: (
1025px,
1280px
),
tv: 1281px
);
@mixin respond-to($breakname) {
/* 1. 讀取斷點對象屬性值 */
$bp: map-get($breakpoints, $breakname);
/* 2. 類型判斷是否為數(shù)組 */
@if type-of($bp) == "list" {
/* 3. 取出數(shù)組中的數(shù)據(jù) */
$min: nth($bp, 1);
$max: nth($bp, 2);
@media screen and (min-width: $min) and (max-width: $max) {
@content;
}
/* 4. tv 大屏 */
} @else if type-of($bp) == "number" {
@media screen and (min-width: $bp) {
@content;
}
} @else {
@warn "`$breakname` is not a valid breakpoint name.";
}
}