ホームページ  >  記事  >  ウェブフロントエンド  >  img および特別なlayout_html/css_WEB-ITnose でのブラウザー レンダリングの分析

img および特別なlayout_html/css_WEB-ITnose でのブラウザー レンダリングの分析

WBOY
WBOYオリジナル
2016-06-24 11:37:50975ブラウズ

Filler

インライン要素は置換要素と非置換要素に分けられます (理解できない学生は Baidu で検索できます)。一方、置換要素は特殊なインライン要素です。独自の size 属性を使用すると、そのサイズを再度設定できます。

この記事は、CSS を使用する上で一定の基礎を持っている学生に適しています

場合

以下に示すようなレイアウトを実装したい場合、これは私が自分のブログを運営していたときに遭遇した問題です:

左側の 3 つの単語は、サイズ 1000*1000 ピクセルの画像です。属性

display:block;height:30%; もちろん、これらの 3 つの単語は親要素の幅を拡張します。その幅はピクチャの現在の幅です。このようにして、左側のサイドバーの幅を適応させることができます。

---これはレイアウトのアイデアです。

問題

このようなレイアウトは完璧に実装できますが、実際の使用中に、

ウィンドウをズームすると、非常に特殊な問題が発生しました。次に、コードを貼り付けて、2 つのスケーリング アニメーションを示します。 :

<style>div{    height: 100%;    float: left;    background: yellow;}img{    display: block;    height: 50%;}</style><div>    <img src="......"></div>

ウィンドウが縮小されると

:
img の高さが変更され、それに応じて幅も変更されることがわかります (ブロックに設定されている場合のみ幅が変更されます) が、その親の幅はdivは変更されていません。

ウィンドウを拡大したときの様子をもう一度見てみましょう

:

ウィンドウの縮小と同様に、imgのサイズは比例して拡大されますが、親divの幅は変更されていないため、親を超えていますdiv

これなぜですか?私と一緒に分析して分析しましょう

分析

ブラウザのサイズが変更されたときに何が起こったのかタイムラインを見てみましょう~

そして、画像内のスタイルの再計算の概要は、影響を受ける要素の数が 1 であることを示しています

下の図のペイント操作に注目してください。 ペイント操作は 3 つの部分に分かれています:

体を描く

  1. 黄色の div を描く
  2. 絵を描く
  3. 黄色の div のサイズは: (342 - 8)、(339 - 8)
描画される画像のサイズは: (174 - 8)、(174 - 8)

ここで 8 はボディの最初のマージンです, divとimgの座標原点は(8,8)です

描画すると黄色のdivの幅は画像と同じではなく、

リサイズ前のサイズを維持します

これはなぜなのかと不思議に思います。その場合の記事から始めましょう 初めに、置換された要素から始めます

webkitから引用 置換された要素とは、オブジェクトの内容がどのように描画されるかがCSSに任されている要素です。要素自体。

置換された要素は、CSS によってレンダリングが指定されていない要素です。レンダリングは CSS とは関係なく、要素自体の内容によって決まります。

したがって、サイズ スタイルを設定しない場合、画像のサイズは独自のレンダリング ルールによって決定されます。そして、

Layout

に制御を与える高さを設定し、次にLayoutがどのように機能するかを見てみましょう:

webkitからの引用

void layout(){     ASSERT(needsLayout());   // Determine the width and horizontal margins of this object.   ...     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {       // Determine if the child needs to get a relayout despite the dirty bit not being set.       ...       // Place the child.       ...       // Lay out the child       child->layoutIfNeeded();      ...   }   // Now the intrinsic height of the object is known because the children are placed   // Determine the final height   ...   setNeedsLayout(false);}
この関数は再帰関数であり、要素をレイアウトするときに次のことがわかります。 ,

は最初にその幅と水平マージン

を決定し、次にサブ要素の位置が決定されると、その拡張された高さに基づいて最終的な高さが決定されます。この仕組みにより、ページの

垂直レイアウト

が人間の 読書習慣 に沿ったものになります (要素はデフォルトの幅などの動作に基づいて表示されます)。ブロック要素の高さは 100%、高さはスタイルまたは内部要素によって決まります)。 これは、外部 div が内部 img の幅を取得できない理由を説明できます。つまり、内部の子をレイアウトするときに div の幅が設定されているため、外部 div の場合は内部要素の幅になります。幅がありません。実際、サイズ変更後にトリガーされる上記のスタイルの再計算は、要素の数を 1 にします。この要素は実際には本体コンテナーのサイズを変更した後、後続のすべての計算がレイアウトに渡されます。

サイズ変更によってトリガーされるレイアウトは、ルートコンテナからの再帰的なレイアウトです

。そのため、次のような親コンテナに基づいて子が配置される状況のみを解決できます: p 要素内のテキスト、テキストは、サイズ変更後に p 要素の幅が小さくなると仮定して、親要素の p の幅に基づいています。上記のレイアウト関数に従って、最初に p 要素のコンテナー要素に基づいて p の幅を設定します。 p 要素の幅に応じてテキストを配置します。テキストが複数の行に詰め込まれている場合、走査が完了した後、p 要素の高さは子 (テキスト) の高さに基づいて決定されます。

幅のパーセンテージに基づいた別のデモンストレーションを行ってみましょう。 すごいです デモ効果は次のとおりです:

完璧です!これは、最も一般的に使用される通常のレイアウト機能のプロセスに基づいたレイアウトであることがわかります。

继续分析

喜欢动脑筋的同学可以读到这一块问题就来了,那么为什么在height:30%的布局下,初次加载没有resize时div为什么可以得到内部的宽度呢???在回答这个问题之前,我们先来看firefox下的表现:

Oh!My God! div竟然没有被撑开,而且宽度为图片的原始宽度,我们先不管这个,来让我们来看一看在Chrome初次加载时发生了什么:

我们可以看到,图片流被一部分一部分的接收,而在接收一定大小的数据后,则会触发Layout,这个Layout则是由img来触发的,它会沿着容器链一路向上进行标记normalChildNeedsLayout或者posChildNeedsLayout位,并接着递归触发layout,而在图像的编码头信息里会包含它的尺寸大小,它会根据这个尺寸并结合img上的style生成计算出img需要占用的尺寸大小,则在后面的图片加载过程中,不会再触发layout,只是去将图片流paint进已经设置好的区域中。

而firefox的黄色div宽度为图片的默认宽度250px,我们可以看出来在Gecko引擎中的layout是没有对img来应用style的,而是直接使用了图像里的编码头信息尺寸,看来webkit还是稍稍地聪明一点,但是他们两个都有一个共同的地方,即对float元素进行重新的宽度计算,这个过程是发生在对其子元素遍历layout结束后来进行的,但是为什么在resize的过程中没有触发对img的宽度重新计算,当黄色div的宽度在初次被初始化后,如果其拥有确定数值并且基础样式为auto时,layout时不再对其宽度进行再次的更改。

解药

这一情况在不同的排版引擎下表现是不一样的,因为其并不是标准的阅读方式,所以也没有统一的标准去规范它,例如在webkit下,我们可以使用js来再次触发img的layout(更改overflow或float等很多值),来使引擎进行再次layout,而这时可以再次对黄色div进行宽度设定,可以推测出该过程在对div进行设置needslayout时先洗冲掉了其的尺寸设定,这样则可以像初始的时候一样获取img的宽度,如下代码:

<!-- 基于上面的代码添加 --><button id="btn">add overflow</button><script>	var img = document.getElementsByTagName('img')[0];		document.getElementById("btn").onclick = function(){		if(img.style.cssText){			img.style.cssText = "";		}else{			img.style.cssText = "overflow:hidden;"		}	}</script>

而这一方法在firefox的Gecko中是无法做到的,本来写此文是想在探索这个问题的最优解法,但是到最后才发现这个问题没有最优的解法,都是很麻烦才能去解决。如我的使用方法是,既然你外部div无法探知到内部基于高度百分比的图片变化,那我就监听resize直接用js来给你丫个宽度(可以参考zhiyishou.com)…………虽然很暴力的解决了,但是还是怎么觉得不开心!

这个问题其实主要原因是img内联元素的特殊性,当它的高度改变时,其宽度也会发生改变,如果我们在这个例子中把img换成一个100px*100px的div,则不会发生这么多排版引擎没有预料到的事情。

结语

浏览器对整套的排版全是以行排列,本文分析了浏览器的主要排版过程,希望对你的对浏览器排版有帮助。

对了,如果你有更优的解决方案,记得告诉我!

Finish.

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。