博客 / 詳情

返回

Less中函數的高級應用,PC、Web移動端適配的良藥偏方

多端適配

熟悉前端開發的一定會遇到這個問題,屏幕適配!有的項目要求同時適配PC、平板和移動端,那我們應該是寫幾套不同的樣式,還是隻寫一套呢?哪一種才是最好的?

其實沒有哪一種最好的,還是得根據項目的需求來定,一般情況下我是推薦只寫一套代碼,因為這樣可以降低開發成本和維護難度。那麼就有個問題,一套代碼如何去適配不同設備?尺寸該用什麼單位?px?em?rem?

我想大部分人的實現無非就那幾種方案:

在頁面初始化的時候做判斷,缺點是不能響應尺寸的變化,頁面需要手動刷新,可以寫一個 resize 監聽事件,當然極少情況下設備屏幕尺寸會發生改變

document.addEventListener("DOMContentLoaded", () => {
    const design = 750;
    const docEl = document.documentElement;
    let clientWidth = docEl.clientWidth;

    if (utils.clientAgent.isPc) {
        // 如果是PC端
    }

    if (clientWidth > 0) {
        docEl.style.fontSize = (clientWidth / design) * 100 + "px";
    }
}, false);

使用 @media 判斷,可以做到尺寸變化的響應,缺點是大量的 @media,可讀性較差,維護起來非常麻煩,感覺還不如寫幾套不同的樣式

@media screen and (max-width: 375px) {
    ...
}

@media screen and (max-width: 576px) {
    ...
}

@media screen and (max-width: 768px) {
    ...
}

安裝各種第三方插件,就是配置項比較多,大多數人選擇的方案

npm install lib-flexible
npm install px2rem-loader
...

以上的幾種方案都可以解決屏幕自適應的問題,使用上沒什麼問題,只不過都是基於 rem 佈局方案,對移動端來説效果是最好的,但是在PC端用 rem 顯然不太合適,那有沒有辦法在PC和移動端切換的時候自動轉換 px 和 rem 單位呢?

Less Functions

參考文檔
能否不用 javascript?直接在 less 中實現自動切換?為了實現這個目的,飯吃不好,覺也睡不好,嘗試了各種各樣的方法,通過 less 各種函數偏方最終實現了。

我用的 less 版本是 3.0,查看最新的版本好像是 4.0 以上了,高版本中多了一些新函數,例如 if、each 等,能更方便的編碼,不過既然能用低版本實現,那兼容性肯定會更強。

實現方法主要是對 value 進行遍歷,length、extract 函數能夠識別空格當成數組對象,遍歷找出數字型的值,通過 @media 查詢自動切換尺寸單位。

原理不難,用 javascript 分分鐘就實現了,但是在 less 中就有點蛋疼了,因為作用域的問題,@media 查詢中的函數無法被外部調用,一開始還是被難住了。

/* 根據不同設備適配屬性單位 */
.mixin-property-rules(@property, @value, @device) {
    @n: length(@value);

    .each(@i, @parent: "") when (@i < @n + 1) {
        @arg: extract(@value, @i);

        /* 屏幕大於或等於768px的設備 */
        .ifNumber() when (isnumber(@arg) = true) and (@device = 001) {
            @child: unit(@arg, px);
        }
        /* 屏幕小於768px的設備 */
        .ifNumber() when (isnumber(@arg) = true) and (@device = 002) {
            @child: unit(@arg * 2 / 100, rem);
        }
        /* 非數值屬性 */
        .ifNumber() when (isnumber(@arg) = false) {
            @child: @arg;
        }

        .ifNumber();
        @newValue: ~"@{parent} @{child}";

        .ifLast() when (@i = @n) {
            @{property}: @newValue;
        }

        .ifLast();
        .each(@i + 1, @newValue);
    }

    .each(1);
}

.mixin-property(@property, @value) {
    /* 屏幕大於768px的設備 */
    @media screen and (min-width: 768px) {
        .mixin-property-rules(@property, @value, 001);
    }
    /* 屏幕小於768px的設備 */
    @media screen and (max-width: 768px) {
        .mixin-property-rules(@property, @value, 002);
    }
}

html {
    font-size: 14px;
    /* 屏幕小於768px的設備 */
    @media screen and (max-width: 768px) {
        font-size: ~"calc(100vw / 1536 * 100)";
    }
    /* 屏幕小於576px的設備 */
    @media screen and (max-width: 576px) {
        font-size: ~"calc(100vw / 750 * 100)";
    }
}

函數調用

.example {
    .mixin-property(padding, 10 20 15 30);
    .mixin-property(border, 1 solid #000);
    .mixin-property(font-size, 16);
}

// 輸出 screenWidth >= 768
.example {
    padding: 10px 20px 15px 30px;
    border: 1px solid #000;
    font-size: 16px;
}

// 輸出 screenWidth < 768
.example {
    padding: .2rem .4rem .3rem .6rem;
    border: .02rem solid #000;
    font-size: .32rem;
}

該函數的優點是你無須寫單位,只寫大小數值,方法會根據設備自動返回單位!如果以後想更改尺寸大小或單位,只需修改函數中的計算邏輯即可,一勞永逸!要説缺點的話就是每個調用的函數在 css 中都會輸出 @media 查詢語句。

提示:函數中的 @media 查詢和數值計算邏輯都是要根據自己需求編寫的,上面只是我寫的例子而已

(・`ω´・) 點贊會有更多原創技術文章分享!

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.