IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    聊聊Top Layer顶层特性的隐患与实践

    张 鑫旭发表于 2024-06-10 16:00:18
    love 0

    by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11213
    本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

    封面图,海边,沙滩,救生圈

    一、好不好用过才知道

    HTML5 <dialog>元素使用showModal()显示的时候,自动层级最高,自动居中,自动有黑色蒙层,明显就比使用show()方法或者设置open属性显示弹框要好。

    于是,就在前段时间,对于LuLu UI Edge主题的弹框组件,我就进行了大刀阔斧的修改,让弹框的显示均采用showModal()方法(通过劫持open属性实现)。

    修改完了自我感觉良好,但是真的实践之后,痛苦的事情来了,由于dialog元素顶层了,因此,自定义的验证提示,浮动定位,toast提示等,全都无法显示,因为这些组件的元素创建都是在body元素下的,由于弹框层级顶级,因此,这些组件样式被覆盖地死死的,用户根本就看不到。

    唯一的方法就是让toast元素,浮层元素全都append到<dialog>元素中,这实在是太麻烦了。

    于是,没办法,妥协,仅alert和confirm类型的弹框使用showModal()显示,其他类型的弹框还是传统的show()方法显示,使用JavaScript进行层级控制。

    可见,看起来很棒的特性真正使用,可能并没有想的那么好。

    就像找对象一样,看起来长得漂亮身材又好,真正相处并不一定自在。

    二、顶层特性说的是什么?

    撤了这么久的“顶层特性”究竟是什么呢?

    MDN上对这个术语有专门的文档,参见:https://developer.mozilla.org/en-US/docs/Glossary/Top_layer

    简而言之,就是浏览器会在文档外创建一个独立的层,这个层正好覆盖整个浏览器视口的宽度和高度,位于页面所有内容之上。

    打开控制台,查看元素,会看到#top-layer的标识,例如:

    #top-layer示意

    一旦看到这个标识,就说明页面有顶层元素了。

    如何创建顶层元素?

    目前来说,创建顶层元素有下面这几种方法:

    • 元素全屏显示,可以通过调用Element.requestFullscreen()方法实现;
    • 上面提到的使用showModal()方法显示的<dialog>元素
    • 使用HTMLElement.showPopover()方法显示的弹出层元素。

    其中,requestFullscreen()可以让任意元素进入全屏显示状态,showPopover()则可以让任意的HTML元素以弹出层的形式显示,我之前写过一篇文章专门介绍,详见“时代变了,该使用原生popover属性模拟下拉了”。

    至于CSS锚点定位(CSS Anchor Positioning API)虽然也是浏览器原生的定位效果,但是,并不会让元素顶层显示,因此,目前,让元素顶层的方法就上面3种。

    三、隐患规避的思考

    要想让自定义的提示效果能在具有顶层特性的Dialog对话框上显示,唯一的办法就是以毒攻毒,也就是自定义提示元素我也弄成顶层元素,顶层元素遵循后显示层级更高的元素,因此,这种方法一定可以让提示元素在对话框之上。

    所以,归根结底,最好的解决方法,那就是把Tips提示或Toast提示效果使用showPopover()方法显示。

    因此,传统组件中的HTMLElement.style.display=”block”这种显示方法就不能使用了,改为给对应的提示元素设置popover属性,然后再调用showPopover()方法。

    这里有个演示案例,交互过程是这样的,点击按钮,显示一个模态对话框,模态对话框中还有个显示toast提示的按钮,点击之后,再显示提示框,注意,这里的提示框是使用showPopover()方法实现的。

    直接HTML就可以完整运行:

    <button onclick="dialog.showModal();">点击我显示模态对话框</button>
    
    <dialog id="dialog">
        <blockquote>
            <button onclick="toast.showPopover();">显示toast提示</button>
            <button onclick="dialog.close();">关闭</button>
        </blockquote>
    </dialog>
    
    <div id="toast" class="toast" popover>我是提示内容</div>

    按照预定的路径连续点击后,就可以看到toast出现在对话框上面啦!

    眼见为实,您可以狠狠地点击这里:popover实现toast提示覆盖顶层对话框demo

    此时,页面中其实存在两个顶层元素,截图示意如下:

    两层顶层元素示意

    改造成本极低,技术上完全可行。

    不过,考虑到兼容性,Safari 23年9月26日才从版本17开始支持,仍有大量用户尚未升级到此版本之上,因此,组件的改造工作还需要再等1年左右,到时候LuLu UI所有这种需要顶层显示的元素全部都采用popover方式实现。

    就目前而言,如果遇到顶层元素覆盖的情况,只能让提示元素当作顶层元素的子元素处理了。

    四、端午节快乐

    这个端午节,连续钓了三条鱼,哈哈哈,收获都还凑合,能明显看出比去年这个时候的自己进步了不少。

    第一天存古垂钓园,140元6小时,钓了31斤。第二天宝沪休闲垂钓,150元6小时,钓了34斤,大热天钓这么多不容易,第三天,兄弟垂钓,100元4小时,钓了18斤。

    具体过程可以参见我的抖音“最会钓鱼的程序员”,欢迎关注哈。

    就是CSS世界精讲视频要delay一天,因为今早带小朋友出去玩,早上赶着出门,没什么时间。

    不知道大家端午过得怎么样呢?

    嘿嘿,就这样吧,一点思考与实践记录。

    嘿嘿

    本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
    本文地址:https://www.zhangxinxu.com/wordpress/?p=11213

    (本篇完)



沪ICP备19023445号-2号
友情链接