草庐IT

快速构建页面结构的 3D Visualization

ChokCoco 2023-03-28 原文

对 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

最后

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

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

有关快速构建页面结构的 3D Visualization的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  3. ruby - 在 Ruby 中构建长字符串的简洁方法 - 2

    在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo

  4. ruby-on-rails - 一般建议和推荐的文件夹结构 - Sinatra - 2

    您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应

  5. ruby - 使用 rbenv 和 ruby​​-build 构建 ruby​​ 失败,出现 undefined symbol : SSLv2_method - 2

    我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby​​2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby​​-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm

  6. ruby - 在 ASP 页面上 Mechanize 中断 - 2

    require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie

  7. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  8. ruby-on-rails - prawnto 显示新页面时不会中断的表格 - 2

    我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.

  9. ruby - 每个页面上的 Jekyll 分页 - 2

    据我们所知,Jekyll默认分页仅支持index.html,我想创建blog.html并在那里包含分页。有什么解决办法吗? 最佳答案 如果您创建一个名为/blog的目录并在其中放置一个index.html文件,那么您可以向_config.yml表示paginate_path:"blog/page:num"。不是使用根文件夹中的默认index.html作为分页器模板,而是使用/blog/index.html。分页器将根据需要生成类似/blog/page2/和/blog/page3/的页面。这将使您到达yourwebsite.com/b

  10. ruby-on-rails - 如何构建复杂的 Rails 系统 - 2

    关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和

随机推荐