phenomLi / Blog

Comments, Thoughts, Conclusions, Ideas, and the progress.
219 stars 17 forks source link

利用css伪类作屏幕断点判断 #7

Open phenomLi opened 6 years ago

phenomLi commented 6 years ago

在进行响应式网页开发时,利用@media screen设置屏幕断点是十分常用的做法:

@media screen and (max-width: 768px) {
    /* your style */
}

@media screen可以判断当前设备的宽度然后使用定义的样式。
但是@media screen只能控制样式,不能控制逻辑。 假如现在有这么一个需求:在屏幕宽度小于768px时,出现弹框。
最常规的做法是用js检测屏幕:

window.onresize = function() {
    if(window.document.documentElement.clientWidth <= 768) {
        alert(window.document.documentElement.clientWidth);
    }
};

可以看到当收缩视口时,会触发弹窗。
但是window.document.documentElement.clientWidth是一个不稳定的属性,他会受到padding,margin,和border以及浏览器设置的影响,有时候并不能精确地获取屏幕宽度的值。而且这种方法的可维护性很差,会造成JS和css的耦合严重,当css断点要改动时js也要一同改动。


那么现在看起来判断屏幕断点的方法最好还是css,但是怎么样能够让css到达断点时通知js呢?用伪类做中介是一个完美的方法。

css通过伪类与js交互

具体的思路是我们用@media query来动态改变某个元素的伪类,然后用js来获取这个元素的伪类的content,然后js根据获取到内容得到当前屏幕的断点。

首先我们在css设置三个屏幕断点:

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

    }

    @media screen and (max-width: 1024px) and (min-width: 768px){

    }

    @media screen and (max-width: 1200px) and (min-width: 1024px) {

    }

然后我们用@media query动态地改变bodyafter


body::after {
        content: '';
        display: none;
    }

@media screen and (max-width: 768px) {
        body::after {
            content: 'small';
        }
    }

    @media screen and (max-width: 1024px) and (min-width: 768px){
        body::after {
            content: 'middle';
        }
    }

    @media screen and (max-width: 1200px) and (min-width: 1024px) {
        body::after {
            content: 'large';
        }
    }

最后我们用js获取bodyaftercontent里面的值:

const content = window.getComputedStyle(document.body, ":after").getPropertyValue("content");

    if(content.indexOf('small') > -1) {
        //小屏幕
    }

    if(content.indexOf('middle') > -1) {
        //中等屏幕
    }

    if(content.indexOf('large') > -1) {
        //大屏幕
    }

之所以上面要用indexOf而不是直接===是因为在某些浏览器下面用js获取到的content会包含双引号(比如会得到"small"而不是small)。

小试牛刀

然后现在我们试一试用这种方法来解决一开始提出的问题:在特定的断点弹窗。
不用改动很多东西,只要在js的判断里面加要的东西就行,简单直接,耦合成度也不高,然后为了更加直观到的效果我把它套进了onresize方法里面:

window.onresize = function() {
    const content = window.getComputedStyle(document.body, ":after").getPropertyValue("content");

    console.log(content);

    if(content.indexOf('small') > -1) {
        alert(content);
    }

    if(content.indexOf('middle') > -1) {
        alert(content);
    }

    if(content.indexOf('large') > -1) {
        alert(content);
    }
}

效果自然是棒棒哒。