scss 封裝媒體查詢工具

背景

以往寫媒體查詢可能是這樣的:

.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 混合功能

sass/scss 快速入門

/* 定義混合函數(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.";
    }
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容