sass 封装媒体查询工具

背景

以往写媒体查询可能是这样的:

css 复制代码
.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 优化一下写法。

目标

希望可以这样写媒体查询:

css 复制代码
.header {
    display: flex;
    width: 100%;
  
    手机: {
     	height: 50px;
    }
  
    平板: {
      	height: 60px;
    }
    ...
}

sass 混合功能

sass/scss 快速入门

css 复制代码
/* 定义混合函数 */
@mixin flexCenter($jus_c: center, $ali_i: center) {
  display: flex;
  justify-content: $jus_c;
  align-items: $ali_i;
}

/* 使用混合函数 */
.header {
    width: 100%;
    @include flexCenter(space-between, flex-end);
}

sass if判断和插槽

混合函数中使用 @if判断区分不同设备,@content类似于 vue 插槽接收使用者在方法体中插入的内容。

css 复制代码
@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;
        }
    }
}

使用:

css 复制代码
.header {
    width: 100%;
    height: 100vh;

    @include respond-to(mobile) {
        height: 100px;
    }

    @include respond-to(tablet) {
        height: 200px;
    }

    ...

    background-color: rgb(139 133 133);
}

上面代码已经基本达到书写媒体查询的目标。但是 if else 太多了,不好看。还可以用策略模式优化一下。

进阶:sass 定义对象优化代码结构

用 hash 映射优化 if,也就是定义一个对象。sass 中可以定义对象。

注意:sass 中()括号就代表 js 的花括号{}和方括号[]

以下就是一个对象,这 5 个属性设置 5 个断点,除最后一个大屏外,其他断点属性值为数组。

之前的代码设置了 4 个断点,区别不大。

css 复制代码
/* 定义断点对象 */
$breakpoints: (
    phone: (320px,480px),
    pad: (481px,768px),
    notebook: (769px,1024px),
    desktop: (1025px,1280px),
    tv: 1281px
);

sass 读取对象中的值:

  • map-get(obj, prop):获取对象的属性值

sass 判断数据类型:

  • type-of($var)
    • 数组类型:list
    • 数值类型:number
css 复制代码
@mixin respond-to($breakname) {
    /* 1. 读取断点对象属性值 */
    $bp: map-get($breakpoints, $breakname);

    /* 2. 类型判断是否为数组 */
    @if type-of($bp) == "list" {
        /* 3. 取出数组中的数据 */
        $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 使用混合函数,可能会报错:

  • [vite] Internal server error: [sass] Undefined mixin.

这是因为 minix 需要预编译,在 vite 中配置:
Vite

css 复制代码
export default defineConfig({
    css: {
        preprocessorOptions: {
            scss: {
                javascriptEnabled: true,
                additionalData: `@use "@/styles/minix.scss" as *;`
            }
        }
    }
});

组件中使用:

css 复制代码
.header {
    width: 100%;
    height: 100vh;

    @include respond-to(phone) {
        height: 100px;
    }

    @include respond-to(tv) {
        height: 200px;
    }

    background-color: rgb(139 133 133);
}

完整代码

css 复制代码
$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. 类型判断是否为数组 */
    @if type-of($bp) == "list" {
        /* 3. 取出数组中的数据 */
        $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.";
    }
}
相关推荐
王哈哈^_^1 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie1 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic2 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿2 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具3 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161773 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test4 小时前
js下载excel示例demo
前端·javascript·excel
Yaml44 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事4 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶4 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json