Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

快速构建 3D Visualization of DOM #210

Open
chokcoco opened this issue Nov 21, 2022 · 0 comments
Open

快速构建 3D Visualization of DOM #210

chokcoco opened this issue Nov 21, 2022 · 0 comments

Comments

@chokcoco
Copy link
Owner

对 Chrome 扩展功能熟悉的小伙伴,可能都有用过 Chrome 的 3D 展示页面层级关系这个功能。

可以通过 控制台 --> 右边的三个小点 --> More Tools --> Layers 打开。即可以看到页面的一个 3D 层级关系,像是这样:

这个功能有几个不错的作用:

  1. 页面层级概览
  2. 快速厘清页面 z-index 层级之间的关系
  3. 用于排查一些重绘过程(滚动过程)页面卡顿

当然,也会存在一些问题,譬如当页面的 DOM 数量太多的时候,这个插件有的时候就会卡到无法交互了。同时,虽然可以快速厘清页面 z-index 层级之间的关系,但是有的时候没法很好的快速看清整个页面嵌套关系。

同时,它只能看整个页面的概览,无法选取部分节点进行观察。

本文,就将介绍一种,快速通过 CSS,构建页面深度关系的 3D 视图,快速清晰的厘清页面 DOM 层级及深度之间的关系。并且可以运用在不同的节点单独进行观察。

当然,总体而言,是基于:

  1. CSS 选择器
  2. CSS 3D 属性

的一次大规模综合应用,整体看完,相信你能学到不少东西。

使用 CSS 构建 3D 可视化 DOM 结构视图

假设,我们首先随时实现一段 DOM 结构,其简单的代码如下:

<div class="g-wrap">
    <div class="g-header">This is Header</div>
    <div class="g-content">
        <div class="g-inner">
            <div class="g-box">Lorem LOrem</div>
            <div class="g-box">Lorem LOrem</div>
        </div>
    </div>
    <div class="g-footer">This is Footer</div>
</div>

部分 CSS 代码:

.g-wrap {
    margin: auto;
    width: 300px;
    height: 500px;
    background: #ddd;
    display: flex;
    align-content: flex-start;
    flex-wrap: wrap;
    flex-direction: column;
    gap: 10px;
    padding: 10px;

    & > div {
        width: 100%;
        flex-grow: 1;
        border: 1px solid #333;
    }
}

.g-content {
    height: 200px;
    display: flex;
    padding: 10px;
    box-sizing: border-box;
    
    .g-inner {
        display: flex;
        padding: 10px;
        gap: 10px;
        
        & > div {
            width: 100px;
            height: 50px;
            border: 1px solid #333;
        }
    }
}

得到这样一个最多深度为 4 层的简单结构:

而我们希望,快速看这个页面的 3D 深度图,像是这样:

又或者,可以使用类似于这样一种 Hover 的交互效果,实现 Hover 某一个 Div,展示出它当前的一个 3D 深度结构图,看看效果:

很有意思的一个效果,到这里应该能明白我们想做一个什么东西了。总的来说,我们的核心需求就是,无论页面的 DOM 结构如何,深度如何,我们希望能够通过一种简单的处理(纯 CSS 实现),能够快速查看页面的 3D 深度结构视图

利用强大的 CSS 选择器,批量处理样式

整个效果看似复杂,其实可以利用 CSS 选择器,很方便的递归调用自己。

因为希望我们的效果可以任意从某一个 DOM 节点处开始,所以,首先,我们需要一个根 CSS 节点,简单的取个名字,为 .g-3d-visual

那么整个 3D 化的样式,我们都会写在 .g-3d-visual 的作用域下:

.g-3d-visual {
    // ...
}

为了让整个代码更易理解,我们会用上 SASS 这种预处理器,主要是利用它的选择器可以的嵌套特性。

至此,我们可以开始构建我们的基础样式,首先我们会处理 2 点:

  1. 整个效果,会稍微的 3D 化,因此会给 .g-3d-visual 根元素添加 3D 相关的样式,譬如 transform-style: preserve-3d,让整个内部元素可以 3D 化
  2. 可以利用通配选择符 *,对 .g-3d-visual 下的所有元素做一个快速的统一处理

那么到这一步,我们的 CSS 代码大概会是这样:

.g-3d-visual {
    transform-style: preserve-3d;
    transform: rotateY(-30deg) rotateX(30deg);

    * {
        position: relative;
        transform-style: preserve-3d;
        transform: translateZ(0);
    }
}

整个图形就变成了这样:

虽然变化不是很多,但是我们已经通过 * 通配符,对内部所有的元素都进行了简单的处理。

图形 3D 化

下一步其实就非常关键了。

我们需要用到元素本身,和元素的两个伪元素,构建元素的立体效果。

举个例子,对于这一块图形:

它的构成是由:

  1. 主体部分由元素本身构成,并且对于结构的每一层,我们通过添加 transform: translateZ(16px),产生不一样的深度
  2. 右侧和下侧的两个面,刚好由元素的两个伪元素通过 transform 旋转不同的角度得到
  3. 整体颜色的调整及阴影

看看代码:

.g-3d-visual {
    transform-style: preserve-3d;
    transform: rotateY(-30deg) rotateX(30deg);

    * {
        position: relative;
        transform-style: preserve-3d;
        background: rgba(0, 0, 255, 0.2);
        transform: translateZ(16px);
        box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.1);

        &::before,
        &::after {
            content: "";
            display: block;
            position: absolute;
            background: rgba(0, 0, 255, 0.2);
        }

        &::before {
            width: 100%;
            height: 16px;
            left: 0;
            bottom: 0;
            transform-origin: center bottom;
            transform: scaleY(1) rotateX(90deg);
        }

        &::after {
            width: 16px;
            height: 100%;
            right: 0;
            top: 0;
            transform-origin: right center;
            transform: scaleX(1) rotateY(-90deg);
        }
    }
}

那么,其实到这里,基本上可以说核心代码都有了,最为核心的是需要理解:

  1. 我们给 .g-3d-visual 下每一层的元素,也就是 * 通配符选择的元素,都添加了一个 transform: translateZ(16px),这一点非常重要,是为了给元素逐渐增加 Z 轴方向的深度
  2. 两个伪元素的运用需要好好理解,它们是用于构建整体的 3D 效果的关键因素
  3. box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.1) 这一个小小的阴影效果的添加,让整个效果看起来更加的真实

这样,我们利用 3 个面,加上简单的阴影,构建了一块一块的立体效果,我们看看目前为止的效果:

按照上述说的,我们可以希望换一种交互方式,实现当鼠标 Hover 到 DOM 的某一层级时,才触发元素 3D 深度变换。

简单改造下代码即可,并且,对于一些重复用到的元素,也可以再利用 CSS 变量统一一下。至此,我们的完整 CSS 代码:

<div class="g-wrap g-3d-visual">
    <div class="g-header">This is Header</div>
    <div class="g-content">
        <div class="g-inner">
            <div class="g-box">Lorem LOrem</div>
            <div class="g-box">Lorem LOrem</div>
        </div>
    </div>
    <div class="g-footer">This is Footer</div>
</div>
:root {
    --side-height: 16px;
    --hover-color: rgba(0, 0, 255, 0.2);
    --box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.1);
    --transform-duration: 0.3s;
}

.g-3d-visual {
    transform-style: preserve-3d;
    transform: rotateY(-30deg) rotateX(30deg);

    * {
        position: relative;
        transform-style: preserve-3d;
        transform: translateZ(0);
        transition: transform var(--transform-duration);
        cursor: pointer;

        &::before,
        &::after {
            content: "";
            display: block;
            position: absolute;
            background: transparent;
            transition: all var(--transform-duration);
        }

        &::before {
            width: 100%;
            height: var(--side-height);
            left: 0;
            bottom: 0;
            transform-origin: center bottom;
            transform: scaleY(0) rotateX(90deg);
        }

        &::after {
            width: var(--side-height);
            height: 100%;
            right: 0;
            top: 0;
            transform-origin: right center;
            transform: scaleX(0) rotateY(-90deg);
        }

        &:hover {
            background: var(--hover-color);
            transform: translateZ(var(--side-height));
            box-shadow: var(--box-shadow);

            &::before,
            &::after {
                background: var(--hover-color);
            }

            &::before {
                transform: scaleY(1) rotateX(90deg);
            }

            &::after {
                transform: scaleX(1) rotateY(-90deg);
            }
        }
    }
}

这样,我们也就得到了题图一开始的 Hover 示意图的效果:

CodePen Demo -- 3D Visualization of DOM

扩展迁移

有了上述代码之后,由于是 SASS 代码,所以记得编译一下,即可拿到完整的 .g-3d-visual 下相关的所有 CSS 代码。

尝试把整段 CSS 代码注入到任意页面后,给你希望观察的节点,添加上 .g-3d-visual 样式即可。

这里我尝试的是,当前正在写作的 Github Issues 页面,看看效果:

当然,可能颜色没有搭配的特别好,但是要知道,整儿页面的 DOM 结构是相当之复杂的。不过整体效果还是很不错的,而且实际操作的过程中,也并不会感觉卡顿。

这一段简单的代码,再简单改造一番,譬如和 Chrome 扩展相结合,快速注入代码,快速指定给哪个元素添加 .g-3d-visual 类名,以及修改配色方案等等,就可以实现一个快速对页面层级进行观察的小插件!

上述效果我是手动修改了当前页面的 HTML 代码,注入的相应的 CSS 代码 :)

总结一下

到这里,我们即可以再简单总结一下完整的步骤:

  • 需要一个整体的 3D 效果,因此需要一个根 CSS 节点,为 .g-3d-visual,并且给它设置好相关的 CSS 3D 属性值,让整个内部元素可以 3D 化
  • 利用通配选择符 *,对 .g-3d-visual 下的所有元素做一个快速的统一处理
  • 利用每个元素的另外两个伪元素,实现每一层效果的 3D 立体感,并且逐层利用 translateZ() 递进深度
  • 通过 :hovertransition 等设置,实现整体的交互效果

当然,这种做法肯定会有一些小问题,譬如如果元素的伪元素已经使用了,那么在 3D 化的效果中,将会被改写。但是由于不是完全覆盖,因此可能会造成一些样式错误。

其次,如果父子两层 DIV 完全是大小一模一样完全重叠在一起,在视觉上也会有些影响。

最后,完整的代码,你可以戳这里获取:CodePen Demo -- 3D Visualization of DOM

最后

好了,本文到此结束,希望本文对你有所帮助 :)

想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant