分类
CSS

内联盒模型-关于line-box的探究(多图预警)

涉及到内联盒模型,应该是css世界中最复杂,最难以理解的模型,本次仅仅探索涉及到内联盒模型的line-box的一些让人难以理解的现象,找到本质原因之后一定会让你足够惊喜。

参考文献(理论基础):https://www.cnblogs.com/10yearsmanong/p/13084706.html

首先看例子

qi ye wei xin jie tu 16145161258073 - 内联盒模型-关于line-box的探究(多图预警)

html

<body>
<div class="z"></div>
<div class="x">
    <span class="a">x</span>
    <span class="b">哇</span>
    <span class="c">移</span>
</div>
<div class="y"></div>
</body>

css

 .z{
            height:100px;
            background:yellow;
        }
        .x{
            font-size:0;
            line-height:0;
        }
        .a{
            font-size:200px;
        }
        .b{
            display: inline-block;
            font-size:20px;
        }
        .c{
            font-size:20px;
        }
        .y{
            height:10px;
            background-color: red;
        }

问题1:line-box是哪个区块?

是红色与黄色之间的白色块,我们可以通过定义证明,vertical-align:top/bottom的定义为与line-box的顶部或底部对齐。于是我们设置.b与.c的vertical-align分别为top和bottom。

qi ye wei xin jie tu 16145168104716 - 内联盒模型-关于line-box的探究(多图预警)

我们确实能够看到‘哇’和‘移’在白色块的上边和下边,但为什么是两字的中间对齐line-box的上边缘与下边缘呢?

问题2:为什么是‘哇’字中间对齐上边缘?

首先我们可以看到‘哇’对应的属性是line-height:0;font-size:20;这个line-height为什么是0呢,就要从该属性说起,line-height是可以继承的,当它是数字的时候,子元素继承的也是数字,当它是百分比或者说数值(12px,1em,1rem,等)它会根据当前font-size的大小计算得出一个具体值然后继承下去(比如font-size:20px;line-height:200%,继承下去的是line-heignt:40px;),因此‘哇’的visual-area的顶部对齐了line-box的顶部。

问题3:什么是visual-area?

就是该内联元素的line-height,既然有了visual-area那就引申出content-area。

3720408019 5a3b79af7559e articlex - 内联盒模型-关于line-box的探究(多图预警)
1496711390 5a3b79b00736d articlex - 内联盒模型-关于line-box的探究(多图预警)

以Baseline基线为0,content-area=fontSize*(ascender-descender+lineGap)/emSquare

其中ascender,descender,lineGap是一款字体定义的属性。

137665312 5a3b79af2f6be articlex - 内联盒模型-关于line-box的探究(多图预警)

基于此line-height:normal也可以计算

line-height:normal=(ascender-descender+lineGap)/emSquare。

因此我们知道content-area只会受font-family和font-size影响。当visual-area大于content-area时,会产生leding,1/2的leading分别加到content-area的上方与下方所以content-area总是处于visual-area中间,当visual-area为0时(line-height:0)就能看到‘哇’字的中间处于line-box上边缘。

问题4:line-box是如何产生的?

首先内联盒模型会产生line-box,它的触发条件时块状盒子内部只有内联元素(inline-block也算)。

问题5:为什么白色区块是line-box?

qi ye wei xin jie tu 16145161258073 - 内联盒模型-关于line-box的探究(多图预警)

首先我们得了解line-box的意义,它决定了一行内联元素所占据文档流的高度,若超出一行,则会重新生成一行line-box。所以每一行line-box的高度可能是不同的。每一行line-box会生成一个宽度为0,font-size为父元素font-size的幽灵子节点(strut)。

要解决这个问题,首先要知道base-line的位置是由什么决定的。

问题6:base-line的位置由什么决定?

若只有一个元素,base-line的位置由ascender与descender共同决定(小写x底部位置),若有多个元素,则由最下方的base-line决定

qi ye wei xin jie tu 16145210404958 - 内联盒模型-关于line-box的探究(多图预警)

首先‘x’,‘哇’,‘移’的line-height均为0,因此他们的实际高度也为0,于是从黄色块下边缘依次排布,content-area在中间位置,得出base-line为‘x’的x下边缘(在所有base-line的最下方)。

而base-line是所有的内联元素共同决定的。它是怎么得出的呢?看下图。

qi ye wei xin jie tu 16145221431830 - 内联盒模型-关于line-box的探究(多图预警)
多个元素决定line-box高度

也许有小伙伴对x的line-height所处位置存疑,请看下图。

qi ye wei xin jie tu 16145225721799 - 内联盒模型-关于line-box的探究(多图预警)
qi ye wei xin jie tu 16145226212275 - 内联盒模型-关于line-box的探究(多图预警)

2021/03/01更新

我们基于最开始的代码,进行一点变更继续探索,首先变更的地方为

  .x{
            font-size:1px;
        }
qi ye wei xin jie tu 16145637328073 - 内联盒模型-关于line-box的探究(多图预警)

问题7:红块为什么会上移?

首先我们将.x元素的font-size设置为1px后,我们在chrome上进行调试,chrome的font-size在1-12px之间时,统一为12px。因此可以有这样一张图。

qi ye wei xin jie tu 16145641934716 - 内联盒模型-关于line-box的探究(多图预警)

因为幽灵字节的的font-size从0上升至12px,因此幽灵字节点的line-height位置由在baseline处往上抬了当前字体在12px时所生成的该x的baseline到该x的1/2content-area的距离。因为在目前line-box中还是幽灵子节点的font-size最小,因此还是取幽灵子节点的line-height位置为最下方,并生成line-box。

问题8:transform对内联元素的影响?

transform属性对display:inline的元素无任何作用,对inline-block的元素有样式上的影响,但对他本身占据的文档流的位置和大小无任何影响。

qi ye wei xin jie tu 16145659814958 1024x403 - 内联盒模型-关于line-box的探究(多图预警)

问题9:vertical-align:text-top/text-bottom对齐的是谁。

幽灵子节点的content-area。以下是证明

qi ye wei xin jie tu 16145665543453 1024x555 - 内联盒模型-关于line-box的探究(多图预警)
qi ye wei xin jie tu 16145666932449 1024x484 - 内联盒模型-关于line-box的探究(多图预警)

问题10:vertical-align:text-top/text-bottom与line-height有关吗?

无关,以下是证明

qi ye wei xin jie tu 16145687882171 1024x484 - 内联盒模型-关于line-box的探究(多图预警)

问题11:为何经过上方设置后,line-box变这么大?

  • 通过各元素的content-area比较得出最下方的baseline为最大的X(幽灵子节点content-area为0)
  • 幽灵子节点加入战场,它的line-height为200px,所处位置为baseline处,但它的visual-area比其他子元素都要大于是由它决定了line-box
qi ye wei xin jie tu 16145692985085 1024x410 - 内联盒模型-关于line-box的探究(多图预警)

问题12:inline-block对line-box有何影响?

inline-block元素的padding,margin,border,height共同组成content-area,inline-block的content-area等于visual-area。

分类
vue

vue组件shadow dom化

当我的npm组件rsa-verify在uni-app样式不起作用,在调查原因后发现uni-app将我的input转为uni-input,因此为input所写的样式失效了。于是需要shandow dom来隔离npm 插件和原生内容。

代码

<template>
  <div class="shadow-dom">
    // 插件内容
    </div>
  </div>
</template>
 shadowDomInit() {
      // 创建shadow dom
      const parentElement = document.querySelector('.shadow-dom');
      const fragment = document.createDocumentFragment();
      fragment.appendChild(parentElement.children[0]);
      const shadowRoot = parentElement.attachShadow({ mode: 'open' });
      shadowRoot.appendChild(fragment);
      const sheet = new CSSStyleSheet();
      // 拷贝样式
      document.styleSheets.forEach(stylesheet => {
        stylesheet.cssRules.forEach(rule => {
          if (rule.selectorText) {
            sheet.insertRule(rule.cssText)
          }
        })
      });
      shadowRoot.adoptedStyleSheets = [sheet];
    },
mounted() {
  this.shadowDomInit();
}

第二种初始化方式

    shadowDomInit() {
                // 创建shadow dom
                const parentElement = document.querySelector('.shadow-protocol-frame');
                const fragment = document.createDocumentFragment();
                fragment.appendChild(parentElement.children[0]);
                const shadowRoot = parentElement.attachShadow({mode: 'open'});
                shadowRoot.appendChild(fragment);
                const style = document.createElement('style');
                style.textContent = `.frame-wrap{flex:1;border:none;overflow:hidden;position:absolute;left:0;top:0;width:110%;height:130%;}#outerContainer{overflow:hidden;}.hide-scroll{position:relative;display:flex;overflow:hidden;flex:1;}.hide-scroll::after{content:'';display:block;}.sign-modal{opacity:0;visibility:hidden;transition:opacity .3s;position:fixed;left:0;right:0;top:0;bottom:0;margin:auto;display:flex;flex-flow:column nowrap;max-height:500px;height:80%;max-width:300px;padding:20px;width:90%;background:white;border-radius:10px;box-shadow:rgba(0,0,0,0.1) 0 2px 15px;}.sign-modal.active{opacity:1;visibility:visible;}.sign-modal-title{text-align:center;}.sign-footer{height:76px;border-top:1px solid #F4F5F6;display:flex;padding:0 5px;justify-content:space-evenly;align-items:center;margin-top:10px;}.reject-button{border-radius:6px;background:rgba(217,220,220,0.30);font-size:16px;color:rgba(0,0,0,0.65);display:flex;justify-content:center;align-items:center;width:115px;height:40px;cursor:pointer;}.agree-button{border-radius:6px;background:#4277BD;font-size:16px;color:white;display:flex;justify-content:center;align-items:center;width:115px;height:40px;cursor:pointer;}`;
                shadowRoot.appendChild(style);
                shadowRoot.adoptedStyleSheets = [style];
            },

注意要点

  • attachShadow的主体不能为template的母元素,因为这会使母元素的非shandow dom子元素无效化。
  • 插件经过shandow dom化后,内部的document.querySelector和document.getElementByid需要转换成document.querySelector(‘.shadowRoot’).shadowRoot.querySelector。因为经过shandow dom化以后,javascript只能使用特殊方法访问节点。