Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Side by Side Diff: third_party/WebKit/Source/core/layout/ng/BlockLayout.md

Issue 2925273007: [LayoutNG] A little bit of documentation on margin collapsing. (Closed)
Patch Set: address comments. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Block Layout #
2
3 This document can be viewed in formatted form [here](https://chromium.googlesour ce.com/chromium/src/+/master/third_party/WebKit/Source/core/layout/ng/BlockLayou t.md).
4
5 ## Floats ##
6
7 TODO.
8
9 ## An introduction to margin collapsing ##
10
11 A simple way to think about margin collapsing is that it takes the maximum margi n between two
cbiesinger 2017/06/13 16:45:25 Can we stay with 80 character lines?
ikilpatrick 2017/06/13 20:42:40 Done.
12 elements. For example:
13
14 ```html
15 <!-- The divs below are 20px apart -->
16 <div style="margin-bottom: 10px;">Hi</div>
17 <div style="margin-top: 20px;">there</div>
18 ```
19
20 This is complicated by _negative_ margins. For example:
21
22 ```html
23 <!-- The divs below are 10px apart -->
24 <div style="margin-bottom: 20px;">Hi</div>
25 <div style="margin-top: -10px;">there</div>
26
27 <!-- The divs below are -20px apart -->
28 <div style="margin-bottom: -20px;">Hi</div>
29 <div style="margin-top: -10px;">there</div>
30 ```
31
32 The rule here is: `max(pos_margins) + min(neg_margins)`. This rule we'll refer t o as the _margin
cbiesinger 2017/06/13 16:45:25 Maybe also link to the CSS spec here (or, at the b
ikilpatrick 2017/06/13 20:42:40 Done.
33 collapsing rule_. If this only happened between top level elements it would be p retty simple,
34 however consider the following:
35
36 ```html
37 <!-- The top-level divs below are -2px apart -->
38 <div style="margin-bottom: 3px">
39 <div style="margin-bottom: -5">
40 <div style="margin-bottom: 7px">Hi</div>
41 </div>
42 </div>
43 <div style="margin-top: 11px">
44 <div style="margin-top: -13px">there</div>
45 </div>
46 ```
47
48 In the above example as there isn't **anything** separating the edges of two fra gments the margins
49 stack together (e.g. no borders or padding). There are known as **adjoining marg ins**. If we apply
50 our formula to the above we get: `max(3, 7, 11) + min(-5, -13) = -2`.
51
52 A useful concept is a **margin strut**. This is a pair of margins consisting of one positive and one
53 negative margin.
54
55 A margin strut allows us to keep track of the largest positive and smallest nega tive margin. E.g.
56 ```cpp
57 struct MarginStrut {
58 LayoutUnit pos_margin;
59 LayoutUnit neg_margin;
60
61 void Append(LayoutUnit margin) {
62 if (margin < 0)
63 neg_margin = std::min(margin, neg_margin);
64 else
65 pos_margin = std::max(margin, pos_margin);
66 }
67
68 LayoutUnit Sum() { return pos_margin + neg_margin; }
69 }
70 ```
71
72 A naïve algorithm for the adjoining margins case would be to _bubble_ up margins . For example each
73 fragment would have a **margin strut** at the block-start and block-end edge. If the child fragment
74 was **adjoining** to its parent, you simply keep track of the margins by calling `Append` on the
75 margin strut. E.g.
76
77 ```cpp
78 // fragment1 is the first child.
79 MarginStrut s1 = fragment1.block_start_margin_strut;
80 s1.Append(node1.style.margin_start);
81
82 builder.SetStartMarginStrut(s1);
83
84 // fragment2 is the last child.
85 MarginStrut s2 = fragment2.block_end_margin_strut;
86 s2.Append(node2.style.margin_start);
87
88 builder.SetEndMarginStrut(s2);
89 ```
90
91 When it comes time to collapse the margins you can use the margin collapsing rul e, e.g.
92 ```cpp
93 MarginStrut s1 = fragment1.block_end_margin_strut;
94 MarginStrut s2 = fragment2.block_start_margin_strut;
95 LayoutUnit distance =
96 std::max(s1.pos_margin, s2.pos_margin) +
97 std::min(s1.neg_margin, s2.neg_margin);
98 ```
99
100 This would be pretty simple - however it doesn't work. As we discussed in the fl oats section a
cbiesinger 2017/06/13 16:45:24 The floats section that just consists of "TODO"? :
ikilpatrick 2017/06/13 20:42:40 Yup, was going to do this in the next patch.
101 _child_ will position _itself_ within the BFC. If we did margin collapsing this way we'd create a
102 circular dependency between layout and positioning. E.g. we need to perform layo ut in order to
103 determine the block-start margin strut, which would allow us to position the fra gment, which would
104 allow us to perform layout.
105
106 We **invert** the problem. A fragment now only produces an _end_ margin strut. T he _start_ margin
107 strut becomes an input as well as where the margin strut is currently positioned within the BFC.
cbiesinger 2017/06/13 16:45:24 I think adding some more details about the bfc off
ikilpatrick 2017/06/13 20:42:40 Yeah I was going to introduce the BFC offset conce
cbiesinger 2017/06/14 21:00:27 OK, I only mentioned it because your code below ma
108 For example:
109
110 ```cpp
111 Fragment* Layout(LogicalOffset bfc_estimate, MarginStrut input_strut) {
112 MarginStrut curr_strut = input_strut;
113 LogicalOffset curr_bfc_estimate = bfc_estimate;
114
115 // We collapse the margin strut which allows us to compute our BFC offset if
116 // we have border or padding. I.e. we don't have an adjoining margin.
117 if (border_padding.block_start) {
118 curr_bfc_estimate += curr_strut.Sum();
119 curr_strut = MarginStrut();
120
121 fragment_builder.SetBfcOffset(curr_bfc_estimate);
122 curr_bfc_estimate += border_padding.block_start;
123 }
124
125 for (const auto& child : children) {
126 curr_strut.Append(child.margins.block_start);
127 const auto* fragment = child.Layout(curr_bfc_estimate, curr_strut);
128
129 curr_strut = fragment->end_margin_strut;
130 curr_strut.Append(child.margins.block_end);
131
132 curr_bfc_estimate = fragment->BfcOffset() + fragment->BlockSize();
133 }
134
135 fragment_builder.SetEndMarginStrut(curr_strut);
136
137 return fragment_builder.ToFragment();
138 }
139 ```
140
141 It isn't immediately obvious that this works, but if you try and work through an example manually,
142 it'll become clearer.
143
144 There are lots of different things which can "resolve" the BFC offset of an elem ent. For example
145 inline content (text, atomic inlines), border and padding, if a child _might_ be affected by
146 clearance.
147
148 ## Zero block-size fragments ##
149
150 TODO.
151
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698