Fundamentals of Web Application Development · DRAFTFreeman

Intro to Layout

The layout of pages is fundamentally dynamic. Even if a page looks completely static to a given user with a certain browser window of a certain size, the page will – and should! – look different to someone else with a different screen.

When reasoning about the layout of our applications, we must think in three directions: for any given element, what is its relationship to its parent element, sibling elements, and its own inner content? Different layout modes in CSS affect these relationships in different ways. Creating layouts in CSS largely consists of defining these relationships and carefully placing constraints on their behavior. So, when thinking about the design of any given element, we ask ourselves: what are its outer constraints, and what are its inner constraints?

Ultimately, our outermost layout constraint is the size of the user’s browser window. Our innermost layout constraints are the atomic size of the content we want to display: the smallest pieces of words, images, video, individual controls or inputs, that cannot be broken apart without losing their meaning or functionality. We can usually make very few assumptions about these ultimate constraints: our users have a multitude of devices and screen sizes, and might resize their browser window at any time, or zoom the text size larger or smaller to make it more comfortable to read. On the other hand, the content being displayed may be largely unknown in advance, generated by your end-users, others in your organization, or arbitrary third-parties, human or machine.

And so our job becomes interestingly challenging.

In this chapter, we will start out looking at the atomic level – how individual elements and their contents are sized and rendered. With those building blocks, we will then explore the different overall layout contexts that CSS provides.

The Box Model

The size of each element, whatever shape it may appear on-screen, is defined by a set of rectangular dimensions. CSS defines a standard Box Model that allows us to size elements as well as the space around them.

There are four layers of essential dimensions on an element. From innermost to outermost, they are the content, padding, border, and margin, as shown below.1

box model diagram
Parts of the CSS Box Model

If an element is given a background (such as a background color or image), the background will extend behind the content and padding. Margins are always transparent as their primary purpose is – using terms from the world of graphic design – to define the negative space or whitespace between elements.

Box Sizing

By default, an element’s width and height dimensions are calculated relative to the element’s content area and do not include padding, border, or margin. This can make it very difficult to reason about layout when trying to precisely size elements, say, to fit in a single line of given width without wrapping. It is common practice to override the default box-sizing property to instead calculate size from the outermost edges of the element’s border:

html {
  box-sizing: border-box;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

We set the root html element’s box-sizing property to border-box so that its calculated dimensions include content, padding, and border – the visual size of the entire rendered element. We then use the universal selector (*) to specify that all elements (and, here, all :before and :after pseudo-elements) should inherit the box-sizing scheme of their parents. This means that all elements on the page will inherit the border-box scheme from the root element unless the property is explicitly overridden for an intermediate ancestor, which allows us to opt-out of border-box at the component level for a given sub-tree of elements.

In the rest of this text, assume that the style box-sizing: border-box; applies everywhere unless otherwise stated.

Flow Context: block and inline Elements

The term document flow is used to describe the behavior of how element boxes are laid out on the page in relation to each other. When discussing document flow, we often refer to the block and inline dimensions. The inline dimension is the primary direction in which text is read – in English, for example, this is horizontally from left to right. The block direction is orthogonal, from top to bottom. In other languages and writing modes, these logical directions (inline, block) may correspond to different physical directions (left, right, top, bottom).

In a block formatting context, HTML elements can be generally categorized as block or inline based on their element type. While there are many subtleties to these flow behaviors, it can be generally described that:

  • block elements take up the entire width of their container, always creating a line break before and after themselves, while
  • inline elements only take up as much vertical and horizontal space as the size of their content necessitates. This means that many short inline elements can flow onto one line, and the contents of a single long inline element – usually text – can, if needed, break and wrap onto multiple lines to fit within the width of its containing block context.

For example, a paragraph p element is block-level by default. If multiple p elements are siblings then they will each break and start on a new line, even if their combined text content is short enough such that it could theoretically fit onto one line if “squished”.

On the other hand, a hyperlink a element is inline by default; its contained text can “run in” with surrounding text or other inline elements on the same line, or break in the middle such that it starts on the end of one line and wraps to the beginning of another line.

To prescribe these behaviors, CSS defines an appropriately-named display property.

display: block;

Explicitly causes an element to create a block-level box in the layout.

display: inline;

Explicitly causes an element to create an inline-level box in the layout.

For layout purposes, inline elements collapse their size to the minimum required to fit their contained content. If an element has a computed display value of inline, then its vertical sizing parameters (height, margin-{top,bottom}, and padding-{top,bottom}) do not affect the layout of other inline elements around it.

![figure.png]

<style>
  span.decorated {
    border: 1px solid blue;
    padding: 1em;
    background-color: rgba(0, 0, 255, 0.1);
  }
</style>
<!-- -->
<div>
  Lorem ipsum sit amet, consectetur adipiscing elit, sed do eiusmod tempor
  incididunt ut labore et dolore <span class="decorated">magna aliqua.</span>
  Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
  aliquip ex ea commodo consequat.
</div>
Lorem ipsum sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

display: inline-block;

As one might expect, a display value of inline-block exhibits behaviors of both inline and block values.

display: none;

Setting display: none; will remove the element, along with all of its descendants, from the render tree. They will still exist in the DOM, but for layout purposes it will appear as though they do not exist.

Position

An element with a position value other than static is considered positioned. Keep this in mind when reading documentation for other CSS properties, as some can have different end results depending on whether or not an element or any of its ancestors are positioned. (Re-read the definition for absolute above.)

static

With a position of static, the element is laid out as normal in the document flow (this is the default value).

relative

If an element’s computed position is relative, the browser will reserve space for the element where it would normally appear in the flow (as if it had a position of static). The element is then offset relative to its normal position depending on other assigned movement values. Other elements remain laid out as if the element were still in its normal static position.

If no movement values are specified, then the element appears as if it had a position of static. However, the element is still considered positioned.

css layout

absolute

A position of absolute removes the element completely from the document flow; that is, other elements in the flow are laid out as if this element did not exist. The element is positioned relative to its closest positioned ancestor based on other assigned movement values.

fixed

Like absolute, a position of fixed also removes the element from the document flow. Its position, specified by other assigned movement values, is relative to its closest transformed ancestor, or to the viewport (the browser window) if it has no transformed ancestor. If relative to the viewport, the element is thus fixed onscreen and does not move when the page is scrolled.

The “movement values” mentioned in these definitions are the other CSS positioning properties top, right, bottom, and left, which can be assigned length or percentage values in order to define the element’s position. The names of these properties refer not to the direction of the movement, but rather to the side of the element which is being “pushed”. This naming can seem non-intuitive at first, but you will quickly get used to it as you work with CSS.

We might usually think of elements as flat boxes taking up 2-dimensional space on the screen, pushing one another around in the document flow. However, as you can see in the example above, positioned elements can overlap. The visual layering of these elements is determined by their calculated stacking order in the current stacking context, and for positioned elements this order can be manipulated using the property z-index. I recommend reading MDN’s guide Understanding CSS z-index,2 especially if you find that your interface requires complex element stacking.