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

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: 80-col 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](https://www.w3.org/TR/CSS2/box.h tml#collapsing-margins)
12 is that it takes the maximum margin between two 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
33 to as the _margin collapsing rule_. If this only happened between top level
34 elements it would be pretty simple, 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
49 fragments the margins stack together (e.g. no borders or padding). There are
50 known as **adjoining margins**. If we apply our formula to the above we get:
51 `max(3, 7, 11) + min(-5, -13) = -2`.
52
53 A useful concept is a **margin strut**. This is a pair of margins consisting of
54 one positive and one negative margin.
55
56 A margin strut allows us to keep track of the largest positive and smallest
57 negative margin. E.g.
58 ```cpp
59 struct MarginStrut {
60 LayoutUnit pos_margin;
61 LayoutUnit neg_margin;
62
63 void Append(LayoutUnit margin) {
64 if (margin < 0)
65 neg_margin = std::min(margin, neg_margin);
66 else
67 pos_margin = std::max(margin, pos_margin);
68 }
69
70 LayoutUnit Sum() { return pos_margin + neg_margin; }
71 }
72 ```
73
74 A naïve algorithm for the adjoining margins case would be to _bubble_ up
75 margins. For example each fragment would have a **margin strut** at the
76 block-start and block-end edge. If the child fragment was **adjoining** to its
77 parent, you simply keep track of the margins by calling `Append` on the margin
78 strut. E.g.
79
80 ```cpp
81 // fragment1 is the first child.
82 MarginStrut s1 = fragment1.block_start_margin_strut;
83 s1.Append(node1.style.margin_start);
84
85 builder.SetStartMarginStrut(s1);
86
87 // fragment2 is the last child.
88 MarginStrut s2 = fragment2.block_end_margin_strut;
89 s2.Append(node2.style.margin_start);
90
91 builder.SetEndMarginStrut(s2);
92 ```
93
94 When it comes time to collapse the margins you can use the margin collapsing
95 rule, e.g.
96 ```cpp
97 MarginStrut s1 = fragment1.block_end_margin_strut;
98 MarginStrut s2 = fragment2.block_start_margin_strut;
99 LayoutUnit distance =
100 std::max(s1.pos_margin, s2.pos_margin) +
101 std::min(s1.neg_margin, s2.neg_margin);
102 ```
103
104 This would be pretty simple - however it doesn't work. As we discussed in the
105 floats section a _child_ will position _itself_ within the BFC. If we did margin
106 collapsing this way we'd create a circular dependency between layout and
107 positioning. E.g. we need to perform layout in order to determine the
108 block-start margin strut, which would allow us to position the fragment, which
109 would allow us to perform layout.
110
111 We **invert** the problem. A fragment now only produces an _end_ margin strut.
112 The _start_ margin strut becomes an input as well as where the margin strut is
113 currently positioned within the BFC. For example:
114
115 ```cpp
116 Fragment* Layout(LogicalOffset bfc_estimate, MarginStrut input_strut) {
117 MarginStrut curr_strut = input_strut;
118 LogicalOffset curr_bfc_estimate = bfc_estimate;
119
120 // We collapse the margin strut which allows us to compute our BFC offset if
121 // we have border or padding. I.e. we don't have an adjoining margin.
122 if (border_padding.block_start) {
123 curr_bfc_estimate += curr_strut.Sum();
124 curr_strut = MarginStrut();
125
126 fragment_builder.SetBfcOffset(curr_bfc_estimate);
127 curr_bfc_estimate += border_padding.block_start;
128 }
129
130 for (const auto& child : children) {
131 curr_strut.Append(child.margins.block_start);
132 const auto* fragment = child.Layout(curr_bfc_estimate, curr_strut);
133
134 curr_strut = fragment->end_margin_strut;
135 curr_strut.Append(child.margins.block_end);
136
137 curr_bfc_estimate = fragment->BfcOffset() + fragment->BlockSize();
138 }
139
140 fragment_builder.SetEndMarginStrut(curr_strut);
141
142 return fragment_builder.ToFragment();
143 }
144 ```
145
146 It isn't immediately obvious that this works, but if you try and work through an
147 example manually, it'll become clearer.
148
149 There are lots of different things which can "resolve" the BFC offset of an
150 element. For example inline content (text, atomic inlines), border and padding,
151 if a child _might_ be affected by clearance.
152
153 ## Zero block-size fragments ##
154
155 TODO.
156
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