Advanced application of functions in less, a good medicine for PC, web and mobile terminal adaptation

Time:2021-9-16

Multi terminal adaptation

Familiar with front-end development will encounter this problem, screen adaptation! Some projects require adaptation to PC, tablet and mobile terminal at the same time. Should we write several different styles or only one? Which is the best?

In fact, there is no best one. It still has to be determined according to the needs of the project. Generally, I recommend writing only one set of code, because it can reduce the development cost and maintenance difficulty. So there is a question, how does a set of code adapt to different devices? What unit should the size be in? px? em? rem?

I think most people’s implementation is nothing more than those schemes:

Judge during page initialization. The disadvantage is that it cannot respond to changes in size. The page needs to be refreshed manually. You can write a resize listening event. Of course, in rare cases, the device screen size will change

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

    if (utils.clientAgent.isPc) {
        //If it is PC terminal
    }

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

Using @ media judgment, you can respond to size changes. The disadvantage is that there are a large number of @ media, which is not readable and very troublesome to maintain. I think it’s better to write several sets of different styles

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

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

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

Installing various third-party plug-ins is the solution most people choose because there are many configuration items

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

The above schemes can solve the problem of screen adaptation. There is no problem in use, but they are all based on the REM layout scheme, which has the best effect on the mobile terminal, but it is obviously inappropriate to use REM on the PC terminal. Is there any way to automatically convert PX and REM units when switching between PC and mobile terminal?

Less Functions

Reference documents
Can I not use JavaScript? Realize automatic switching directly in less? In order to achieve this goal, I can’t eat well and sleep well. I tried a variety of methods and finally realized it through less various function partial prescriptions.

The less version I use is 3.0. It seems that the latest version is more than 4.0. There are some new functions in the higher version, such as if and each, which can be encoded more conveniently. However, since it can be implemented in the lower version, the compatibility will be stronger.

The implementation method is mainly to traverse the value. The length and extract functions can recognize the space as an array object, traverse to find the numeric value, and automatically switch the size unit through @ media query.

The principle is not difficult. It can be implemented in minutes with JavaScript, but it’s a little painful in less. Because of the scope problem, the functions in @ media query can’t be called externally. At the beginning, it’s still difficult.

/*Adapt attribute units according to different devices*/
.mixin-property-rules(@property, @value, @device) {
    @n: length(@value);

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

        /*Devices with screens greater than or equal to 768px*/
        .ifNumber() when (isnumber(@arg) = true) and (@device = 001) {
            @child: unit(@arg, px);
        }
        /*Devices with screens smaller than 768px*/
        .ifNumber() when (isnumber(@arg) = true) and (@device = 002) {
            @child: unit(@arg * 2 / 100, rem);
        }
        /*Non numeric attribute*/
        .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) {
    /*Devices with screens larger than 768px*/
    @media screen and (min-width: 768px) {
        .mixin-property-rules(@property, @value, 001);
    }
    /*Devices with screens smaller than 768px*/
    @media screen and (max-width: 768px) {
        .mixin-property-rules(@property, @value, 002);
    }
}

html {
    font-size: 14px;
    /*Devices with screens smaller than 768px*/
    @media screen and (max-width: 768px) {
        font-size: ~"calc(100vw / 1536 * 100)";
    }
    /*Devices with screens smaller than 576px*/
    @media screen and (max-width: 576px) {
        font-size: ~"calc(100vw / 750 * 100)";
    }
}

function call

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

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

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

The advantage of this function is that you do not need to write units, but only case upper and lower values. The method will automatically return units according to the device! If you want to change the size or unit in the future, just modify the calculation logic in the function, once and for all! The disadvantage is that each called function will output @ media query statements in CSS.

Tip: the @ media query and numerical calculation logic in the function should be written according to their own needs. The above is just an example I wrote

(・` ω ´ (1) more original technical articles will be shared in the praise!