WebCore Rendering IV – Absolute/Fixed and Relative Positioning
The position property in CSS can be used to position an object relative to a specific containing block. It has four values: ‘static’, ‘absolute’, ‘fixed’ and ‘relative’. Static positioning is the default and means that the object is just positioned using the normal rules of block and line layout.
Relative positioning is exactly like static positioning except that the CSS left, top, right and bottom properties can be used to apply a translation to the object. The
isRelPositioned method can be used to ask if a renderer is using relative positioning.
bool isRelPositioned() const
The translation offset that will be applied can be obtained using the following methods:
int relativePositionOffsetX() const; int relativePositionOffsetY() const;
Relative positioning is literally nothing more than a paint-time translation. As far as layout is concerned, the object is at its original position. Below is an example that uses relative positioning to shift part of a line up by a few pixels. As you can see, the line lays out as though the object was at the original position.
<div style="border:5px solid black; padding:20px; width:300px"> Here is a line of text. <span style="position:relative;top:-10px; background-color: #eeeeee"> This part is shifted<br> up a bit, </span> but the rest of the line is in its original position. </div>
Absolute and Fixed Positioning
Fixed positioned objects are positioned relative to the viewport, i.e., the visible page area of your browser window. Absolute positioned objects are positioned relative to the containing block, which is the nearest enclosing ancestor block with a position other than ‘static’. If no such block exists, then the initial containing block (the RenderView) is used. For more details on containing blocks, see the previous article.
isPositioned method can be used to find out if a renderer is absolute or fixed positioned.
bool isPositioned() const
When an object is absolute/fixed positioned, it becomes block-level. Even if the CSS display type is set to inline (or inline-block/table), the effective display type becomes block-level once an object is positioned. The
isInline method will return false for positioned elements.
RenderStyle can give both display values. There are times where the original display type is relevant and needed by layout, and the following methods can be used to obtain both display types.
EDisplay display() const; EDisplay originalDisplay() const;
The Positioned Objects List
Every block has a positioned objects list that contains all of the absolute/fixed positioned renderers for which it is the containing block. It is the block’s responsibility to place these positioned children. The following methods can be used to manipulate the positioned objects list:
void insertPositionedObject(RenderObject*); void removePositionedObject(RenderObject*);
layoutOnlyPositionedObjects method is used to lay out only the positioned objects for a block. If only positioned objects changed, then this method returns
true. This indicates that the layout method doesn’t have to lay out any of its normal children and can just return early.
layoutPositionedObjects method takes care of the placement of positioned objects. It takes a boolean argument that indicates whether relayout should be forced on all of the objects. Relayout can be necessary under a variety of circumstances that will be covered in future articles.
bool layoutPositionedObjects(bool relayoutChildren)
Coordinates of Positioned Objects
The coordinates of positioned objects in CSS are relative to the padding edge of the containing block. For example specifying a left and top position of (0, 0) for an absolute positioned object will result in the object being placed just inside the containing block’s top left border. Here is an example:
<div style="position:relative;border:5px solid black;width:300px;height:300px;"> <div style="position:absolute;width:200px;height:200px;background-color:purple"></div> </div>
In WebCore, coordinate positions are always relative to the border edge, so in the above example, the object is actually at (5, 5).
When the desired coordinates are omitted from CSS, WebCore has to determine an appropriate place for the positioned object. CSS has a set of extremely complex rules for this, which we will delve into in more detail in future articles.
Inline Relative Positioned Containers
It is possible for a relative positioned inline to act as a “containing block” for an absolutely positioned descendant. This is another extremely complex edge case that warrants its own article. For now it is enough to know that such a construct is possible, and that the code does have to deal with it.