vrijdag 18 juni 2010

Overlap makes you think

In my thesis I investigate the possibility of developing a tool that visualizes any web page as a 3D model. If you don't know what I am talking about, here's a video of the first mock up.


In my last post I explained the basic concepts behind the box model and CSS positioning. Now we can build upon that knowledge and see how well it plays with DomScape. In this post I will explain what the problem is with overlap caused by negative margin. Through the analysis of the consequences of overlap I have come to a better understanding what DomScape is and what constraints it implies. I will show that we have to let go of the Matryoshka metaphor and that we need a new algorithm to calculate the z-values of the elements.

Negative margin
With the margin property it is possible to reposition an element, but a margin can also be set to a negative value. If the negative value is big enough the element is displayed outside the boundaries of the containing block. This is demonstrated in the next figure.

The element breaks out of the boundaries of the containing block and is even be wider than it, because it has a negative left margin (from CSS: The Definitive Guide)

When an element is repositioned, it is likely that it will overlap a neighboring element. Which of the  elements is displayed on top depends on the properties of the browser that renders the web page. "Browsers usually render elements in order from beginning to end, so a normal-flow element that comes later in the document can be expected to overwrite an earlier element, assuming the two end up overlapping," Meyer explains in CSS: The Definitive Guide. 

Overlapping elements present a problem for DomScape, because so far it has assumed that every element stays within the boundaries of its containing block. This is clearly not the case for elements with a negative margin and the same could be said for elements that have a absolute or relative position or are set to overflow. The exact effect of these properties will be discussed in later posts - for now we can just simply say that they cause overlap.

The overlap caused by negative margin forced me to rethink what exactly DomScape is and how it could deal with overlap. What follows now is the result of my attempt to formalize DomScape and the challenges it faces.

Constraints
DomScape visualizes a web page as a 3D object by exploding the HTML elements over the z-axis. Elements keep their position on the x,y-plane and DomScape assigns a z-value to each element. DomScape needs an algorithm that automatically computes a z-value for each element, while also honoring certain constraints at the same time. What kind of constraints are we talking about?

Discernible elements
Every element in a web page occupies a certain x,y-space. Because a child element is confined to the x,y-space of its parent (unless it has been displaced), it overlaps its parent to some extent. Most elements will thus share their space with other elements. Overlapping elements can be hard hard, if not impossible, to visually distinguish. DomScape makes elements discernible by making sure that elements cannot overlap in the x,y,z-space. When elements occupy the same x,y-space, they'll need different z-values.

Keep elements in context
DomScape is a tool that gives the user more insight into why a web page looks the way it does. The HTML structure has a big influence on the layout, because it not only defines what elements exist in the web page, but also through the element hierarchy how elements relate to each other. DomScape must visualize the relationships that exists between elements to keep those elements in their respective contexts. The z-value of an element has of course a big effect on the perceived relationship it has with other elements. Elements that effect each other, e.g. parent and child elements, need to be close to each other. If the elements are unnecessarily far apart from each other, it would drastically lower the user's ability to understand why the layout looks the way it does.

Smooth transition
Another constraint is that the transformation between the 2D and 3D view is continuous. This is demonstrated in the video when the web page appears 2D, but is actually 3D when the user pans around it. What really happens is that the normal web page view is a 2D projection (from the top) of the 3D model. The 2D perspective is 'just another' (orthogonal) view on the the 3D model.

Overlap
From last point automatically follows that if two elements overlap on the x,y-plane, the element that is rendered on top in the 2D view is required to have the highest z-value. This is of course because the web page view is a 2D projection from the top.

Overlap seems very straight-forward until you start considering the abnormal overlap that can occur through different kinds of CSS properties: negative margin, absolute and relative positioning and overflow. They can be used to displace an element so that it overlaps a neighboring element. An element that overlaps another element needs higher z-value than the element it overlaps, even when the overlapping occurs because one of the items is displaced. 

Finding the right algorithm
The reason I specifically mention overlap caused by element displacement, is because it excludes a certain algorithm which I had in my mind since the conception of DomScape. Inherent to the Matryoshka metaphor is that you don't have to look at the x,y-space the element occupies, but only at its position in the HTML hierarchy. The following figure shows that when we base the z-value of each element on its hierarchical position certain elements will have the same z value although they occupy the same x,y-space.

Two rows of HTML elements with basic layout and the z-values in the bottom-left corners. The z-values are based on the position of the element in the hierarchy. This work fine in the first row when all elements stay within their parents boundaries, but violate the discernability constraint in the second row when elements are displaced.

In the first row the only that occurs is by child elements overlapping their parents. The z-values are as you might aspect: none of the elements has a z-value higher than 3. In the second row the elements are displaced through negative margin and this creates a lot of overlap. Note that the fourth block (with the '... no margin' text) has not been displaced in any way by its margins: it's in the same position in both rows. However, because the fourth block occurs later in the code, it is rendered later and overwrites the third block.

Displaced elements show us that we need to take in account the x,y-position of all elements. We know that if an element overlaps another element, the overlapping element must be at least one unit higher than that element. This guarantees that no element occupies the same x,y,z-space as any other element does and that the elements are in the right order. The following figure shows what happens when we calculate the z-values in this manner.

Elements and their z-values in DomScape. In the first row the z-values are the same when using the hierarchical method. The z-values in the second row become quite high, but maintain the discernability constraint.

This example demonstrates that in this approach high z-values can easily occur through overlap - even in items that haven't been explicitly made to overlap other elements. The following algorithm is used to compute z values for all elements in the figure above.

z: z-value of an element  
E: collection of all elements  
F: collection of elements with calculated z

for every element e in E:
  z of e = 0
  for every element f in F:
    if e overlaps with f
      z of e = 1 + z of f

  add e to F

Context constraint
This algorithm demonstrates how we can calculate the z-value of every element, but it doesn't solve the context issue of displaced elements. Because it is possible to displace an element by such an amount that it becomes unclear what the containing block of the element is, it looses its layout context. Well, of course the layout context won't have gone anywhere, but it will hard - if not impossible - for the user to figure that out without any visual cues. DomScape will have to incorporate a method of visually linking child elements to their parents to make it is easy for users to keep track of the DOM hierarchy and the layout context of each element.

Vertical lines connect elements to help the user understand the layout context of each element. Such lines could also work very well when elements are displaced (from the DomScape concept video).

In the concept video I have used vertical lines to help the user see where an element begins and ends compared to its parent. In general, we could say that the lines visualize the layout context of an element. In this example the lay out context is very straight-forward and easy to understand, but with displaced elements these lines can be very valuable in determining what the containing block of the element is, where the element would have been if it weren't displaced and how the element affects the positioning of its siblings. Future DomScape prototypes will test to what extent these lines are helpful and help maintain the context constraint.

Conclusion
Before I talked about certain problematic CSS properties, mainly relative and absolute positioning, float and overflow. I have shown that the overlap caused by margins can be properly visualized by using a different algorithm to calculate z-values. In future posts I will look at the alternative CSS positioning schemes to see if they can be approached in the same way as I have done in this post.

Basics of CSS positioning

In my thesis I investigate the possibility of developing a tool that visualizes any web page as a 3D model. If you don't know what I am talking about, here's a video of the first mock up.




In my last post I took a dive into my first research question: Is the DomScape visualization possible? Apparently CSS positioning is a bit more complex than I first imagined, because I ended up more confused than I was before I wrote that post. I finished the post with the intent to research the CSS 2.1 Specification. Especially the parts that revolve around the positioning of elements are subject of my research: Section 8. Box model, Section 9. Visual formatting model and Section 10. Visual formatting model details. In theory those documents are all I need - in practice they are rather technical and very, very dry.

Good thing I found CSS: The Definitive Guide by Eric Meyer, which is a very comprehensive and detailed book on CSS. It's a bit dated, but the concepts behind the CSS 2.1 specification haven't changed anyway. It basically goes through the entire specification to explain how CSS is meant to work and what the intricacies are. Because Meyer focuses a lot on edge cases his book is good way to find out where potential challenges lie for DomScape.

Matryoshka metaphor
In the last post I also introduced the concept of the Matryoshka or 'landscape' metaphor, which I use to indicate a certain property of the DomScape visualization. It means that the way DomScape makes a 3D representation of a 2D web page, is guaranteed to work if each element in the web page stays within the boundaries of its parent. There are several CSS properties that break the Matryoshka metaphor, because they do allow an element to extent outside the borders of its parent. As far as I currently understand, this is possible through these CSS properties: relative and absolute positioning, float and overflow

The Matryoshka metaphor: elements stack upon each other without any overlap outside the boundaries of a lower element (taken from the DomScape concept video

In order to understand how these special CSS positioning schemes work, it is important to get the basics out of the way first. I failed to do this in my last post and I have come to realize that it is hard to discuss advanced CSS positioning without first introducing the core principles of CSS positioning: the CSS box model, normal flow and the containing block.

Box Model
At the heart of CSS positioning lies the box model. Meyer explains the box model as follows, "CSS assumes that every [HTML] element generates one or more rectangular boxes, called element boxes. Each element box has a content area at its core. The content area is surrounded by optional amounts of padding, borders, and margins." In addition to this, the content area can contain any number of other elements/boxes. This creates an hierarchy of elements of which the root element is the browser's viewport.  


 Content area and its surroundings (from CSS: The Definitive Guide)



There are two types of boxes, inline boxes and block boxes. Inline boxes are used to layout text and are generated by elements such as span, a, strong and em. In the default CSS positioning scheme, called normal flow, inline boxes are flowed (placed) horizontally - from left to right in Western languages. Inline elements stack next to each other and wrap to the next line if there's no horizontal space left.

The same inline element: first without and then with line wrapping (from CSS: The Definitive Guide)

Block boxes on the other hand are generated by elements such as div, p and table and are flowed vertically, even if there's space to flow them horizontally. By default a block box fills up the entire horizontal space it is given, unless the width of the element is set to a different value, as is demonstrated in the figure below.

 
Two consecutive block elements (with different content, widths and margins) are flowed vertically (from Mike Hall's article on CSS Positioning).

It is possible to control whether a box is displayed as inline or block by setting the display property to inline or block. This doesn't however if the element is inline or block, but just how it is displayed.

Containing block
Every element has a containing block, which defines where in the web page the element should be rendered. In case of normal flow, Meyer explains, "the containing block is formed by the content edge of the nearest block-level, table cell, or inline-block ancestor box." Often it will be the parent element that is the containing block its children. Note that an inline element can never be a containing block in normal flow.

CSS2.1 also defines a series of rules for determining an element's containing block when the element is not in normal flow, for example when an element is floated or positioned. I will discuss these properties in a later post.   

Conclusion
These are the building blocks of basic CSS positioning. Every HTML element is converted to a graphical box. The CSS is used to adjust the default positioning. By setting the height, width, margin, padding and border it is possible to change how and where an element is rendered. In my next post I will explain what happens when a negative margin is used to position an element outside its parent.