© Martine Dowden and Michael Dowden 2020
M. Dowden, M. DowdenArchitecting CSShttps://doi.org/10.1007/978-1-4842-5750-0_4

4. Layouts

Martine Dowden1  and Michael Dowden1
(1)
Brownsburg, IN, USA
 

Individual elements form a layout when they are put together on a page. Using CSS we rely on the box model to control the width and behavior of each element without the layout. To control how elements place themselves in relationship to each other, we can use properties such as display and float. In this chapter we define the box model and look at float, flex, inline-block, and grid for specific layouts.

Box Model

The base for laying out content is rooted in the box model which describes the rectangular boxes that are generated for elements in the document tree. As shown in Figure 4-1, the content is enveloped by three boxes: padding, border, and margin.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig1_HTML.png
Figure 4-1

Box Model

Each of these properties, including the content, will be governed by dimension, type, positioning, relationship to other elements, and external information.

Box Sizing

Box-sizing , or the property that defines the height and width of an element, by default has a value of content-box which means that when a width and height is defined for an element, it is only applied to the content. Adding padding or margin to the element therefore increases the percentage width of the total available viewport that the element utilizes.

Content-Box

If a two-column layout, with each div equaling 50% of the width of the viewport, is desired, the amount of padding applied to each column needs to be subtracted from the width given to the element or the total width of both elements will exceed 100%.

Consider a viewport of 800px wide containing two divs. If no padding, margin, or border is added to the divs, and they are each given a width of 50%, their combined width will equal 100% of the viewport. If they are floated, they will sit perfectly side by side and take up 100% of the screen such as in Figure 4-2.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig2_HTML.png
Figure 4-2

Content-Box No Padding

If padding is added to the columns, the width of the columns will increase by the padding amount, causing them to exceed the width of the viewport. Figure 4-3 shows the columns with added padding.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig3_HTML.png
Figure 4-3

Content-Box With Padding

If the divs are floated, the second would therefore be pushed below the first as their combined width is now greater than 100% of the container such as seen in Figure 4-4.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig4_HTML.jpg
Figure 4-4

Effects of Padding and Border When Using box-sizing: content-box

In Code
Let’s take the earlier described scenario and put it in code (Listings 4-1 and 4-2; output shown in Figure 4-4).
<body>
  <h1>No Padding</h1>
  <div class="container">
    <div>
      <p>Content</p>
    </div>
    <div>
      <p>Content</p>
    </div>
  </div>
  <h1>With Padding</h1>
  <div class="container has-padding">
    <div>
      <p>Content</p>
    </div>
    <div>
      <p>Content</p>
    </div>
  </div>
</body>
Listing 4-1

HTML

.container { overflow:auto; }
.container > div {
  width: 50%;
  float: left;
}
.container p {
  background: rgba(0, 0, 0, .16); /* light grey */
  text-align: center;
}
.container > div:last-of-type p { /* second rectangle */
  background: rgba(0, 0, 0, .32); /* dark grey */
}
.has-padding > div {
  outline: dashed 1px rgba(0, 0, 0, .5);
  padding: 10px;
}
Listing 4-2

CSS

Border will behave the same way as padding; therefore, any border width applied will need to be included in the sum of content and padding to calculate the full width or height of the elements included in the layout.

Margin Collapse

Margins behave a little differently than padding. When sibling elements both have padding, padding from both is applied, and the space between the two elements is the sum of both sets of padding. Margin, however, depending on their context, can collapse. Margin collapsing is when top and bottom margins are combined or collapsed into a single margin equal to the largest of the margins applied such as in Figure 4-5 or, if all margins are negative, the size of the most negative margin. Left and right margins do not collapse.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig5_HTML.png
Figure 4-5

Margin Collapsing

Margins will collapse when
  • There is nothing separating the margin of the parent and the margin of its child including padding, border, inline parts, block formatting context, or clearance property clear (e.g., clear: right, used with floats).

  • Elements are adjacent siblings except if the latter needs to be cleared past floats (more about floats later in this chapter).

  • Even when one of the margins is equal to 0.1

In Code
When two divs with 10 pixels worth of padding each are set side to side, they will only have 10 pixels of vertical margin between them (as seen in Listings 4-3, 4-4, and Figure 4-6).
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig6_HTML.jpg
Figure 4-6

Margin Collapse

<body>
  <div>Content</div>
  <div>Content</div>
</body>
Listing 4-3

HTML

div {
 margin: 10px;
 background: rgba(0, 0, 0, .16); /* light grey */
}
div:last-of-type {
 background: rgba(0, 0, 0, .32); /* dark grey */
}
Listing 4-4

CSS

However, if we take the earlier example, where the columns have been floated and replace the padding for margin, notice that the margin does not collapse. The columns will still stack as their combined total width is greater than 100% [50 %  + (2 x 10px)] x 2 = 105%, but because the divs are floated, the margins do not collapse. See Figure 4-7.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig7_HTML.jpg
Figure 4-7

Floated Divs No Margin Collapse

Unlike border, which can be applied to any element regardless of type, both margin and padding have restrictions as to which elements they can be applied to. Padding cannot be set on elements whose display property value is
  • table-row-group(<tbody>)

  • table-header-group (<thead>)

  • table-footer-group (<tfoot>)

  • table-row (<tr>)

  • table-column-group

  • table-column

Margin cannot be set on elements with table display types (e.g., <tr>, <td>, etc.) except table, inline-table, and table-caption.2

Pros and Cons

Although the mixins pixels and percentage-based values can lead to some interesting math, the benefit of keeping the box-sizing value as content-box is that when a width or height value is assigned to the content, it will not be subject to side effects from the padding added. The content will be exactly the height or width it was assigned by the developer. Furthermore, because it is the default value, the element’s sizing will exhibit “normal” expected behavior without having to know anything about the other properties already set on the element.

Special Case: Outlines and Box Shadows
Outlines and box shadows, which create boxes around the border, could be thought of belonging to the box model. This is not the case because outlines and box shadows do not take up space. They overlay themselves, similarly to a position absolute as described in Figure 4-8.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig8_HTML.png
Figure 4-8

Outline and Box Shadow

The outline and box shadow not only overlap the content below but also bleed out of the viewport without the ability to scroll to it. Because they do not take up space, it does not constitute overflow, and the scroll bar is therefore not triggered. See Figure 4-9 and Listings 4-5 and 4-6.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig9_HTML.jpg
Figure 4-9

Box-Shadow and Outline Do Not Occupy Space in the Layout

<body>
  <h1>Outline</h1>
  <div class="container outline">
    <div>Content</div>
    <div>Content</div>
  </div>
  <h1>Box-Shadow</h1>
  <div class="container box-shadow">
    <div>Content</div>
    <div>Content</div>
  </div>
  <h1>Both</h1>
  <div class="container outline box-shadow">
    <div>Content</div>
    <div>Content</div>
  </div>
</body>
Listing 4-5

HTML

.container div {
  background: rgba(0, 0, 0, .16); /* light grey */
  height: 50px;
}
.container div:last-of-type {
  background: rgba(0, 0, 0, .32); /* dark grey */
}
.container.outline div:last-of-type {
  outline: dotted 15px rgba(0, 0, 0, .5);
}
.container.box-shadow div:last-of-type {
  box-shadow: 0px 0px 10px 10px rgba(0, 0, 0, .5)
}
Listing 4-6

CSS

When both outline and box-shadow are set, they will overlap each other.

Border-Box

As described earlier, box-sizing: content-box has some disadvantages when mixins absolute units and percentage-based units. Content-box can also add extra complexity when setting content as a percentage of total width or height when the content has padding.

This is when border-box comes in. Assigning box-sizing: border-box changes how an element’s width and height is calculated. Instead of encompassing just the content, it takes in the content, padding, and border. When padding or border is added, the width and height of the content itself is therefore decreased. See Figure 4-10.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig10_HTML.png
Figure 4-10

Border-Box with Padding

So if we take the first example of the two floated columns, we will see that the two columns retain a width of 50%. The margin still behaves the same way as with content-box. Listings 4-7 and 4-8 and Figure 4-11 show the same example as in Figure 4-4 using box-sizing: border-box instead of the default box-sizing: content-box.
<body>
  <h1>No Padding or Margin</h1>
  <div class="container">
    <div>
        <p>Content</p>
    </div>
    <div>
      <p>Content</p>
    </div>
  </div>
  <h1>With Padding</h1>
  <div class="container has-padding">
    <div>
      <p>Content</p>
    </div>
    <div>
      <p>Content</p>
    </div>
  </div>
  <h1>With Margin</h1>
  <div class="container has-margin">
    <div>
      <p>Content</p>
    </div>
    <div>
      <p>Content</p>
    </div>
  </div>
</body>
Listing 4-7

HTML

.container { overflow:auto; }
.container > div {
  width: 50%;
  box-sizing: border-box;
  float: left;
}
.container p {
  background: rgba(0, 0, 0, .16); /* light grey */
  text-align: center;
  margin: 0;
}
.container > div:last-of-type p { /* second rectangle */
  background: rgba(0, 0, 0, .32); /* dark grey */
}
.has-padding > div {
  border: dashed 1px rgba(0, 0, 0, .5);
  padding: 10px;
}
.has-margin > div {
  border: dashed 1px rgba(0, 0, 0, .5);
  margin: 10px;
}
Listing 4-8

CSS

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig11_HTML.jpg
Figure 4-11

Element Using Border-Box

Box-sizing is not inherited. It will need to be applied to all elements for which it needs to be changed.

Display

Margin and padding allow for manipulating the display of the element; the display property manipulates how elements are displayed in relationship to one another by specifying the type of rendering the box uses for the element.

The display property has been at the cornerstone of layouts on the Web since the inception of CSS. Table 4-1 shows when each display value was added to the specification.
Table 4-1

Display Property Values by CSS Version3

Level 1

Level 2

(Revision 1)

Level 3

1996

2011

2018

block

inline

list-item

none

inline-block

table

inline-table

table-row-group

table-header-group

table-footer-group

table-row table-column-group

table-column

table-cell

table-caption

inherit

Contents

flow-root

run-in

inline list-item

flex *

inline-flex *

grid *

inline-grid *

ruby**

*Candidate recommendation

**Working draft

Inline

Considered flow content, inline elements are placed inline with the text when in a flow layout. By default, the following elements are inline:
<a>, <abbr>, <acronym>, <audio> (if it has visible controls), <b>, <bdi>, <bdo>, <big>, <br>, <button>, <canvas>, <cite>, <code>, <command>∗∗, <data>, <datalist>, <del>, <dfn>, <em>, <embed>, <i>, <iframe>, <img>, <input>, <ins>, <kbd>, <keygen>*, <label>, <map>, <mark>, <meter>, <noscript>, <object>, <output>, <picture>, <progress>, <q>, <ruby>, <s>, <samp>, <script>, <select>, <slot>, <small>, <span>, <strong>, <sub>, <sup>, <svg>, <template>, <textarea>, <time>, <u>, <tt>, <var>, <video>, <wbr>4

*Deprecated

**Obsolete

When the content is displayed inline, by default elements go from left to right and set themselves side to side, width permitting. By default, elements, regardless of padding, and margin, will align themselves to the text baseline. If the width does not permit, the content will wrap below, as demonstrated in Figures 4-12 and 4-13 and Listings 4-9 and 4-10.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig12_HTML.png
Figure 4-12

Inline Elements

<body>
    I am some text.
    <span>I am a span.</span>
    More text goes here.
    <code>I am code.</code>
    And some more text.
    <a href="">I am an anchor tag.</a>
</body>
Listing 4-9

HTML

body {
  font-size: 24px;
  padding: 36px;
  margin: 0;
}
a {
  padding: 10px;
  outline: dotted 2px grey;
}
code {
  margin: 10px;
  outline: dotted 2px grey;
  outline-offset: 8px;
}
Listing 4-10

CSS

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig13_HTML.jpg
Figure 4-13

Element Using border-box

Block Elements

Also considered flow content, block elements stack atop one another unless they are affected by another property such as float.

The following elements are block-level elements by default:5
<address>, <article>, <aside>, <blockquote>, <details>, <dialog>, <dd>, <div>, <dl>, <dt>, <fieldset>, <figcaption>, <figure>, <footer>, <form>, <h1>, <h2>, <h3>, <h4>, <h5>, <h6>, <header>, <hgroup>, <hr>, <li>, <main>, <nav>, <ol>, <p>, <pre>, <section>, <table>, <ul>
Figures 4-14 and 4-15 show the default behavior for block-level elements.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig14_HTML.png
Figure 4-14

Default Block-Level Behavior Diagram

By default, block-level elements will take the full width of the viewport. If a width is applied, even if there is still enough room inline of the element, the block element will still place itself below the previous. See Listings 4-11 and 4-12.
<body>
  <div>Content</div>
  <div>Content</div>
  <div>Content</div>
</body>
Listing 4-11

HTML

html, body {
  font-size: 24px;
  padding: 36px;
  margin: 0;
}
div {
  background: rgba(0, 0, 0, .16);
  height: 50px;
  margin: 20px;
  outline: dotted 1px gray;
  outline-offset: 19px;
  text-align: center;
}
div:first-of-type {
  padding: 20px;
}
div:nth-of-type(2),
div:last-of-type {
  width: 200px;
}
Listing 4-12

CSS

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig15_HTML.jpg
Figure 4-15

Default Block-Level Behavior

If an inline element is placed after a block element, the inline element will still be placed after the block element as seen in Listings 4-13, 4-14, and Figure 4-16.
<body>
  <div>Block Content</div>
  <span>Inline Content</span>
</body>
Listing 4-13

HTML

html, body {
  font-size: 24px;
  padding: 36px;
  margin: 0;
}
div {
  background: rgba(0, 0, 0, .16);
  height: 50px;
  width: 200px;
}
Listing 4-14

CSS

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig16_HTML.jpg
Figure 4-16

Block and Inline

Inline-Block

Inline-block utilizes concepts from both block and inline. It will behave like a block element but flow with the surrounding content as if it were inline. A common use case for inline-block is horizontal navigation; see Listings 4-15 and 4-16 and Figure 4-17.
<body>
  <nav>
    <ul>
      <li><a href="">Home</a></li>
      <li><a href="">About</a></li>
      <li><a href="">Contact</a></li>
    </ul>
  </nav>
</body>
Listing 4-15

Inline-Block HTML

html, body {
  font-size: 24px;
  padding: 36px;
  margin: 0;
}
ul {
  margin: 0;
  padding-left: 0;
  background: lightgray;
}
li {
  list-style-type: none;
  display: inline-block;
  margin: 2rem;
}
a {
  padding: 1rem 2rem;
  background: white;
  border-radius: 2rem;
}
Listing 4-16

Inline-Block CSS

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig17_HTML.jpg
Figure 4-17

Inline-Block

The default behaviors of inline, block, and inline-block elements are not enough to create the layouts often desired. Before such options as grid and flex were introduced in 2018 or float, introduced until 1996,6 we relied on tables even when the data was not tabular. For a long time, this was the only option in creating some more complex layouts, as even if the CSS specification described better methods, browsers did not necessarily support them. Today, this is no longer the case, and the use of tables for display purposes is now thoroughly frowned upon as it prevents assistive technologies from properly conveying the content being displayed to the users. Some exceptions, such as e-mail templates, still exist. Similarly to why historically they had been used for display purposes in web sites, most e-mail clients have little to no support for CSS layout properties, but the accessibility concerns remain and therefore tables for layout should be avoided whenever possible. For general web use, however, using tables for layouts is considered bad form and inaccessible. We are going to cover three commonly used patterns for laying out content: float, flexbox, and grid.

Float

Unlike flex and grid, float is not part of the display property, but a property in and of itself.

A great use case for float is when a figure is included within text, allowing text to flow around the figure such as in Figure 4-18.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig18_HTML.png
Figure 4-18

Floated Image

Creating layouts using float, however, was much more difficult. Let’s look at an example that uses the following HTML (Listing 4-17).
<body>
  <h1>Flexbox</h1>
  <nav>
    <ul>
      <li>Nav Element</li>
      <li>Nav Element</li>
      <li>Nav Element</li>
    </ul>
  </nav>
  <div class="container">
    <section>
      <div><span>1</span></div>
      <div><span>2</span></div>
      <div><span>3</span></div>
    </section>
    <main>
      <h2>Main Content</h2>
      <p>Lorem ipsum dolor sit amet, consectetur... </p>
      <img src="./image.png" alt="">
      <p>Varius morbi enim nunc faucibus a. Ut placerat... </p>
      <p>Eget duis at tellus at urna condimentum mattis... </p>
    </main>
    <aside>
      <h2>Aside</h2>
      <p>Placerat duis ultricies lacus sed turpis tincidunt id aliquet... </p>
    </aside>
  </div>
</body>
Listing 4-17

Example HTML

And we are going to try to achieve the layout in Figure 4-19 .
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig19_HTML.jpg
Figure 4-19

Layout Example

Starting with the navigation, we already see a problem in Figure 4-20 (Listings 4-18 and 4-19).
html, body {
  padding: 36px;
  margin: 0;
}
h1 {
  text-align: center;
}
nav {
  border-top: solid 1px gray;
  border-bottom: solid 1px gray;
}
nav ul { padding: 0; }
nav li {
  list-style-type: none;
  width: 33%;
  float: left;
}
Listing 4-18

Float: CSS

Once the list items are floated, the border rises up over them, and our numbers from the left-hand column come set themselves to the left of it (Figure 4-20).
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig20_HTML.jpg
Figure 4-20

Floated Navigation

In order for the numbers to behave, the float must be cleared. We can use display: flow-root on the list in order to clear the float. This is a fairly new property. Historically a class of “clearfix” or “group” (see Listing 4-19) would have been added to the list.
.clearfix::after {
  content: "";
  clear: both;
  display: table;
}
Listing 4-19

Clearfix

Continuing down the page, we can get close to the target layout (Figure 4-19) with floats (see Listing 4-20 and Figure 4-21); however, the column just doesn’t line up at the bottom of the screen. Centering the numbers in the left column to look evenly distributed when the window is resized and the content reflows doesn’t work either. Furthermore, since padding is used to center the numbers, if content was edited for a full sentence instead of a number, the padding would have to be recalculated or the text would no longer be centered.
html, body {
  padding: 36px;
  margin: 0;
}
h1 {
  text-align: center;
}
nav {
  border-top: solid 1px gray;
  border-bottom: solid 1px gray;
  display: flow-root;
}
nav ul {
  padding: 0;
  margin: 0;
}
nav li {
  box-sizing: border-box;
  list-style-type: none;
  float: left;
  padding: 1rem;
  text-align: center;
  width: 33.33%;
}
section {
  float: left;
  background: rgba(0, 0, 0, .16);
}
section div {
  box-sizing: border-box;
  color: white;
  background: rgba(0, 0, 0, .50);
  height: 100px;
  width: 100px;
  text-align: center;
  padding: 37px;
  margin-top: 5rem;
  margin-bottom: 5rem;
}
main {
  background: rgba(0, 0, 0, .05);
  box-sizing: border-box;
  padding: 30px;
  float: left;
  width: calc(100vw - 244px - 30%)
}
aside {
  box-sizing: border-box;
  background: rgba(0, 0, 0, .16);
  width: 30%;
  padding: 30px;
  float: right;
}
img {
  width: 100%;
  max-width: 250px;
  float: left;
  padding-right: 20px;
}
Listing 4-20

CSS for Figure 4-21

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig21_HTML.jpg
Figure 4-21

Attempt a Layout Using Floats

Getting the text around the image worked really well, as it is what float was designed to do. The rest of the layout had some issues, however. The padding and combination of a set height and width would more than likely make longer content expand out of its container in the far-left bar. Also of concern, 100% is not easily divisible by 3, so depending on how the browser decides to calculate the width of each nav element, content could be pushed around in ways it was not supposed to. Lastly the background on the columns just doesn’t line up.

For all of these reasons, this would be a bug-prone and hard-to-maintain layout. To achieve this layout, and have the UI be fluid, the use of tables, the CSS display: table property, and/or JavaScript would have been required before flexbox and grid were introduced.

Flexbox

Historically , two types of layouts that were incredibly difficult, both found in the earlier example, included:
  • Multiple columns where the background color is to align no matter the content within them

  • Centering content vertically

Today we have flexbox. Solving those two problems is where flex really shines. Flexbox also allows for dynamically determining the width of the column based on the amount of content. Using display: flex is particularly useful when creating a layout that necessitates control over the spacing of elements across a container.

Let’s try to create our layout again, using flexbox this time (Listing 4-21).
h1 { text-align: center; }
nav {
  border-top: solid 1px gray;
  border-bottom: solid 1px gray;
}
ul {
  display: flex;
  padding-left: 0;
  justify-content: space-around;
}
.container { display: flex; }
aside {
  background: rgba(0, 0, 0, .16);
  flex-basis: 30%;
  flex-shrink: 0;
  padding: 30px;
}
section {
  background: rgba(0, 0, 0, .5);
  align-items: center;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
}
section div {
  color: white;
  background: rgba(0, 0, 0, .50);
  align-items: center;
  display: flex;
  height: 100px;
  justify-content: center;
  width: 100px;
}
main {
  background: rgba(0, 0, 0, .05);
  padding: 30px;
}
li { list-style-type: none; }
img {
  width: 100%;
  max-width: 250px;
  float: left;
  padding-right: 20px;
}
Listing 4-21

Flexbox CSS

Dissecting the preceding layout, we apply flex to three areas of the layout, the three content columns, the navigation, and the far-left column itself. For both the far-left column and in the navigation, flex is used in order to distribute the content across their container vertically and horizontally, respectively.

Flex-Direction

Flexbox is applied on two axes: main and cross. The main axis defines the direction of the layout. The property flex-direction is used on the container and includes four options: row, row-reverse, column, and column-reverse, where row is the default. This will determine the order in which elements will be displayed and the direction of the layout (see Figure 4-22).
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig22_HTML.png
Figure 4-22

Flexbox Main Axis

Flexbox will by default try to fit all of the content onto one line but can be made to let the content wrap by using the flex-wrap property. The flex-wrap property can take any of the following values (Figure 4-23):
  • nowrap This is the default. All items will be placed on one line following the main axis and cause overflow if necessary.

  • wrap Items will wrap from top to bottom.

  • wrap-reverse Items will wrap from bottom to top.

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig23_HTML.png
Figure 4-23

Wrap

By adding to row, column, or wrap, we can alter the sequence in which elements are displayed. If we want to move a specific element in the sequence individually, we can use order. The property takes an integer, by default 0. If an element is assigned a 1, and all others are set to the default 0, it will appear at the end. If assigned a -1, the element will appear at the beginning. The order is therefore based on the sequence provided and then weighted based on values assigned to each element using the order property.

Justify-Content

To determine the position of each element across the main axis, we use justify-content on the container. Possible values are as follows:

flex-start  Elements are placed at the beginning of the container. Flex-start is the default value.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figa_HTML.png
flex-end Elements are placed at the end of the container.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figb_HTML.png
center  Elements are placed at the center of the container.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figc_HTML.png
space-between Elements are spaced evenly across the container with no space between the edges of the container and the first and last items.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figd_HTML.png
space-around Elements are spaced evenly across the container with half as much space between the edge of the container and the first and last items as between the other items.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fige_HTML.png
space-evenly Elements are spaced evenly across the container with the same amount of space between the edges and the first and last elements and between the elements.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figf_HTML.png
Inline-Block

Flex-start, middle, and flex-end have some advantages over inline-block. For many use cases, the use of display: inline-block in conjunction with text-align can achieve the same result; however, inline-block has some intricacies regarding spacing. Even when margins are set to 0, a small gap will appear between elements. A layout where the sum of the elements equals 100% of the width of the container therefore becomes challenging to create. Let’s look at the code and its output (Listings 4-22 and 4-23 and Figure 4-24).

Example 1

<body>
  <h1>Example 1</h1>
  <nav>
    <ul>
      <li>inline-block element</li>
      <li>inline-block element</li>
      <li>inline-block element</li>
    </ul>
  </nav>
</body>
Listing 4-22

Inline-Block HTML

html, body {
  padding: 12px 36px;
  margin: 0;
  font-size: 32px;
}
ul {
  padding-left: 0;
}
li {
  display: inline-block;
  padding: 10px 20px;
  background: grey;
  color: white;
}
Listing 4-23

Inline-Block CSS

../images/487079_1_En_4_Chapter/487079_1_En_4_Fig24_HTML.jpg
Figure 4-24

Inline-Block Gap

Notice the gap between the inline-block elements. There is no margin on the list element. Flexed items do not suffer from this unintended behavior.

Align-Items and Align-Self

The cross-axis is perpendicular to the main axis. Looking back at our original flexbox example (Figure 4-24), we have three columns of content, the left number section, the middle content section, and the right aside. For each of them to have the same length, denoted by their respective background colors aligning at the bottom, we can use the align-content property. The values are as follows:

stretch Elements will expand to the available height of the container (width if flex-direction is column).
../images/487079_1_En_4_Chapter/487079_1_En_4_Figg_HTML.png

For the purposes of columns, this behavior allows flexed elements to grow in size, similarly to a table row, so that all the elements included will have the same height as the latest in the array.

flex-start or start Elements will align to the top of the container, similarly to vertical-align: top.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figh_HTML.png
flex-end or end Elements will align to the bottom of the container, similarly to vertical-align: bottom.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figi_HTML.png
center Elements will align to the middle of the container, similarly to vertical-align: middle .
../images/487079_1_En_4_Chapter/487079_1_En_4_Figj_HTML.png
baseline Elements will align to the text baseline, similarly to vertical-align: baseline.
../images/487079_1_En_4_Chapter/487079_1_En_4_Figk_HTML.png

The preceding properties are set on the container and will apply to all elements within. To manipulate a single element and make it behave differently from the others, we can use align-self. Its values are the same as those available for align-items, listed earlier.

Flex-Basis, Flex-Grow, and Flex-Shrink

Flex-basis allows for setting a base width elements should start at. Their content will determine whether they need to grow or shrink to fit the space available in the container.

To ensure that content fills 100% of the available space in the container, a flex-grow property can be applied. By default set to 0, it specifies the growth factor of the flexed item. This value is ratio based. If all siblings of the container have the same value, then they will all grow by the same amount so that the sum of the elements equals 100% of the available width (or height if flex-direction is set to column). Otherwise it will be distributed according to the ratio defined on each flexed element.

Flex-shrink works similarly to flex-grow but for shrinking content to prevent overflow. By default set to 1, it can be set to 0 and used in conjunction with flex-basis to ensure a flexed element has a fixed width (or height if flex-direction is set to column).

Because of its ability to dynamically deal with the space provided, display-flex makes generating fluid designs and aligning content easier than ever before, without resorting to the use of tables for display purposes but it is very one directional. Grid, however, brings in the second dimension.

Grid

Also fairly recently introduced is grid. Where grid shines is that it gives the developer the ability to name sections making the code easy to read and maintain. Unlike flexbox which only deals with one direction at a time, grid allows for rows and columns to be defined. These sections can be names such as in Listing 4-24, or based on the row and column number such as in Listing 4-26 .
.container {
 display: grid;
 grid-template-columns: 1fr 1fr 1fr 300px;
 grid-template-rows: 46px auto 36px;
 grid-template-areas:
   "header header header header"
   "main main . sidebar"
   "footer footer footer sidebar";
}
Listing 4-24

Grid CSS

Grid-template-columns defines four columns. The first three of equal width and the last of 300px. The “fr” unit used here represents a fraction of leftover space as a ratio.7 The last column will be given a width of 300 pixels; the other three will receive equal amounts of leftover space as their width.

Grid-template-rows defines three rows, the first with height and last with height of 46 and 36 pixels, respectively. The middle row, set to auto, will adjust its height to accommodate its content.

Grid-template-areas defines, on the 4 by 3 grid just created, named areas by row as seen in Figure 4-25.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig25_HTML.png
Figure 4-25

Grid Template Areas

So looking at a full implementation, the code will look and output looks as follows (Listings 4-25 and 4-26). Figure 4-26 displays the output.
<body>
  <div class="container">
    <header>
      <h2>Header</h2>
    </header>
    <main>
      <h2>Main</h2>
      <p>Lorem ipsum dolor sit amet, consectetur… </p>
      <p>Quisque faucibus, augue sed varius ornare… </p>
    </main>
    <aside class="sidebar">
      <h2>Sidebar</h2>
      <ol>
        <li>Lorem</li>
        <li>Ipsum</li>
        <li>Dolor</li>
        <li>Sit</li>
        <li>Amet</li>
      </ol>
    </aside>
    <footer>
      <h2>Footer</h2>
    </footer>
  </div>
</body>
Listing 4-25

Grid HTML

html, body {
  padding: 36px;
  margin: 0;
}
header {
  grid-area: header;
  background: rgba(0, 0, 0, .1);
  text-align: center;
  padding: 5px;
}
main {
  grid-area: main;
  background: rgba(0, 0, 0, .2);
  padding: 10px;
}
.sidebar {
  grid-area: sidebar;
  padding: 10px;
  background: rgba(0, 0, 0, .3);
}
footer {
  grid-area: footer;
  background: rgba(0, 0, 0, .5);
  text-align: center;
  color: white;
}
.container {
 display: grid;
 grid-template-columns: 1fr 1fr 1fr 1fr;
 grid-template-rows: 46px auto 36px;
 grid-template-areas:
   "header header header header"
   "main main . sidebar"
   "footer footer footer sidebar";
}
header, footer {
  display: flex;
  align-items: center;
  justify-content: center;
}
header h2, footer h2 {
  margin: 0;
}
Listing 4-26

Grid CSS

Note the “ . ” on the second row of the grid-template-areas for the container class; this allows for the three-column/second row grid section to remain empty.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig26_HTML.jpg
Figure 4-26

Grid Output

Each UI element is set to its named grid-area. The advantage is the naming can follow the purpose of the container being positioned, making the code easy to read and then maintain. Furthermore, when repositioning elements for responsiveness, the only property that needs to be updated is the grid-template-areas .

Grid also allows for defining areas using column and row numbers. Numbering starts at 1 on the far left for columns and 1 on the very top for rows as depicted in Figure 4-27.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig27_HTML.png
Figure 4-27

Grid Rows and Columns

Using the same HTML and as earlier, we can achieve the same output by assigning grid-row and grid-column values to each section (Listing 4-27).
html, body {
  padding: 36px;
  margin: 0;
}
header {
  grid-area: header;
  background: rgba(0, 0, 0, .1);
  text-align: center;
  padding: 5px;
  grid-row: 1;
  grid-column: 1 / 5;
}
main {
  grid-area: main;
  background: rgba(0, 0, 0, .2);
  padding: 10px;
  grid-row: 2;
  grid-column: 1;
}
.sidebar {
  grid-area: sidebar;
  padding: 10px;
  background: rgba(0, 0, 0, .3);
  grid-row: 2 / 4;
  grid-column: 4;
}
footer {
  grid-area: footer;
  background: rgba(0, 0, 0, .5);
  text-align: center;
  color: white;
  grid-row: 3;
  grid-column: 1 / 4;
}
.container {
 display: grid;
 grid-template-columns: 1fr 1fr 1fr 1fr;
 grid-template-rows: 46px auto 36px;
}
header, footer {
  display: flex;
  align-items: center;
  justify-content: center;
}
header h2, footer h2 {
  margin: 0;
}
Listing 4-27

Grid CSS

Grid-row and grid-column can be defined using a single integer (grid-row: 1) or two integers separated by a / (grid-row: 1/3). When only one integer is used, the section will start that the line specified and span one column or row such as for the main element in the example earlier. When two integers separated by a / are used, the section will start at the line specified by the first integer and end at the line specified by the second, as seen on the footer’s grid-column value.

Similarly to flexbox or table, the placement of content within a section can be adjusted. The justify-items property can be used on the grid container to determine how content within sections or cells will align left to right. Its values are start, end, center, and stretch as illustrated in Figure 4-28. Stretch is the default value.
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig28_HTML.png
Figure 4-28

Justify-Items Values

The same values can be used to change the alignment of a specific cell using the justify-self property on the specific section.

To specify how content aligns vertically in a cell, we can assign the align-items property to the grid container. Its values are the same as earlier and it also defaults to stretch (Figure 4-29).
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig29_HTML.png
Figure 4-29

Vertical Alignment Using Align-Items

Similarly to justify-self, the same values can be used with the align-self property on an individual section to allow for a cell to behave differently than the default set on the container.

Just like flexbox, grid also has a justify-content and an align-items property. They have the same values and work in the same fashion as for flexbox. They position grid cells horizontally and vertically within the container. This can be very useful when the grid itself is smaller than the grid container.

To add space between the cells, grid-gap can be used. This will determine how much space is between each row and/or column. Individually, they can be set using grid-row-gap and grid-column-gap, respectively. For example, grid-gap: 5px 2rem would set a gap of 5 pixels between each row and a gap of 2 rems between each column.

Lastly, grid has an auto-placement algorithm. This will kick in when there are more items to place than what is defined by the CSS, or when an element has a grid-column or a grid-row value that is outside of the bounds defined in the container’s templates. The behavior of the auto-placement is controlled using the grid-auto-flow property. Auto-flow can be optimized for filling
  • By row with row value Fills in rows and adds new rows as necessary

  • By column, using the column value Fills in columns and adds new columns as necessary

To have the grid fill in any gaps that may exist, dense may be added to both the row and column values, grid-auto-flow: column dense.

Grid is now much more widely supported across evergreen browsers but has some compatibility issues in older browsers such as Internet Explorer 11 which currently has an incomplete implementation of the specification.

../images/487079_1_En_4_Chapter/487079_1_En_4_Figl_HTML.gif Accessibility When Using Flexbox or Grid

Grid and flexbox give the ability to reposition and reorder content at will simply by changing just one or two properties regardless of the sequence in the HTML. This can become problematic for accessibility.

The Web Content Accessibility Guidelines states

When the sequence in which content is presented affects its meaning, a correct reading sequence can be programmatically determined. (Level A) Criterion 1.3.2 Meaningful Sequence (Level A)8

When changing the order of elements using CSS, it is important to make sure the programmatic sequence still makes sense.

Responsive Design

At the core of responsive design implementation is the media query.

Media Query

“Media Queries allow authors to test and query values or features of the user agent or display device, independent of the document being rendered. They are used in the CSS @media rule to conditionally apply styles to a document, and in various other contexts and languages, such as HTML and JavaScript.”

—Media Queries Level 49

More specifically, using media queries allows you to conditionally change styles based on the viewport’s properties. Often used in responsive design are media queries related to the viewport’s width, the end goal being to tailor the layout for small mobile screens vs. large desktop monitors, and everything in between. To achieve this technique, breakpoints are chosen at different viewport width(s) where the styles will change. The CSS might look as in Listing 4-28.
@media (min-width: 500px) { ... }
Listing 4-28

Media Query

where anything in between the brackets does not get applied unless the width of the viewport is greater than 500px. Width ranges can also be declared this way (Listing 4-29).
@media (500px <= width <= 700px) { ... }
Listing 4-29

Ranged Media Query

where the styles are applied when the viewport widths are between 500 and 700 pixels.

It is easy to fall into the trap of thinking that the styles need to be rewritten for each of the breakpoints. Furthermore, when going from narrow to wide layouts, far fewer styles need to be overridden than going from wide to narrow. This is because on narrower layouts, items are more likely to be simply stacked than with wide layouts. For most use cases, the easiest way to set up responsiveness to decrease the amount of code being written is to start with the narrow layout and then add on as the screen gets wider. Let’s look at the implementation of this sample design (Figure 4-30).
../images/487079_1_En_4_Chapter/487079_1_En_4_Fig30_HTML.png
Figure 4-30

Responsive Design

To achieve this layout, the HTML in Listing 4-30 will be used.
<body>
  <header>
    <h1>Responsive Design</h1>
  </header>
  <nav>
    <ul>
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
      <li><a href="">Link 3</a></li>
    </ul>
  </nav>
  <h2>My Items</h2>
  <main>
    <article>
      <h3>Article Title</h3>
      <p>Lorem ipsum dolor sit amet, consectetur elit...</p>
      <a href="">Read More</a>
    </article>
    ...
  </main>
</body>
Listing 4-30

Responsive Layout HTML

The first thing we do is establish some base styles that will be applied regardless of screen size (Listing 4-31).
html, body {
  margin: 0;
  padding: 0;
}
body {
  box-sizing: border-box;
  font-family: 'Gill Sans', 'Gill Sans MT', ... sans-serif;
  height: 100vh;
  left: 0;
  margin: 0;
  position: absolute;
  top: 0;
  width: 100vw;
}
h1, h2, h3 {
  font-family: Impact, Haettenschweiler, ... sans-serif;
  margin: 0;
}
header {
  background: rgba(0, 0, 0, .1);
  box-sizing: border-box;
  grid-area: header;
  text-align: center;
  padding: .75rem;
}
nav {
  background: #c6c6c6;
  grid-area: nav;
}
nav ul {
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: space-evenly;
}
nav li { list-style-type: none; }
nav a {
  display: block;
  padding: 1rem;
}
h2 {
  background: #c6c6c6;
  grid-area: title;
  padding: .5rem 1rem;
}
main {
  padding: 1rem;
  grid-area: main;
  overflow: auto;
}
article {
  background: #e9e9e9;
  border-left: solid 2.5rem gray;
  padding: 1rem;
  margin-bottom: 1rem;
}
article a {
  display: block;
  text-align: right;
}
Listing 4-31

Base Styles

We can then add the layout-specific information for each breakpoint (Listings 4-32 and 4-33).
/* Mobile layout */
body {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 4rem auto auto 3rem;
  grid-template-areas:
    "header"
    "title"
    "main"
    "nav";
  height: 100vh;
  overflow: hidden;
}
Listing 4-32

Mobile CSS

/* Desktop layout */
@media (min-width: 500px) {
  body {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    grid-template-areas:
      "header"
      "nav"
      "title"
      "main";
    height: auto;
    overflow: auto;
  }
  main { column-width: 250px ; }
  article { break-inside: avoid; }
  h2 { background: none; }
}
Listing 4-33

Desktop CSS

Notice that in Listing 4-33, it takes very little CSS to readjust the layout for desktop users. This is because base styles are already applied and do not have to be duplicated. We also see here the advantages of named areas for grid layout and the ease of organizing them for the correct layout.

Summary

Elements are subject to the box model, which dictates how its width, padding, margin, and border will behave. When put together, the elements form a layout. There are as many ways to approach a layout as there are layouts to be created, but each technique has its own strengths and weaknesses. We have looked at float, flexbox, and grid as well as media queries for responsive layouts.

In the next chapter, we will look at scenarios where CSS doesn’t seem to work as expected, with a special focus on differences between browsers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.216.18