Chapter 6. Source Order and Display Order

The Holy Grail layout in Chapter 5 illustrated something important about our new layout methods: they enable the visual display of page elements in an order other than that described in the source. This was previously only possible by taking an item out of flow with absolute positioning—something that turned out not to be all that useful for layout. This ability to disconnect visual display and source order can be used for good and bad alike; we’ll look at the benefits (and risks) in this chapter.

Direction of Flow in Flexbox

The default behavior of flex items is to lay themselves out in document order—the order in which they appear in the source. The flexbox specification includes the property flex-direction, which is how we choose whether to display items as a row or as a column. This property can also be used to change the direction in which the flex items lay themselves out.

The following cards display one after the other in the order in which they appear in the source. If I set flex-direction to row-reverse, they flip and start to display from the end of the flex container (Fig 6.1).

.cards {
  display: flex;
  flex-direction: row-reverse;
}

Code example: http://bkaprt.com/ncl/06-01/

Figure

Fig 6.1: The items display in reverse order.

Similarly, if flex-direction is column, you can also choose column-reverse (Fig 6.2).

.cards {
  display: flex;
  flex-direction: column-reverse;
}

Figure

Fig 6.2: The items display in reverse order as a column.

The flex-direction values relate to writing modes. In a right-to-left language, row-reverse would cause the text to start from the left-hand side of the flex container.

Direction of Flow in Grid Layout

If you are explicitly placing items on your grid—either by using line-based placement or template areas—you can avoid Grid auto-placing any items for you. We’ve already seen examples of Grid auto-placement, though. As soon as you create a grid, any direct child flows into that grid—one item per cell. These auto-placement rules can be used in various ways to change the way content flows into the grid.

Where Grid is most like flexbox is in the grid-auto-flow property. By default, this property is set to row. Therefore, when working in a left-to-right language, items start at the top left of the grid container and position themselves into cells working to the right, then move on to the next row. Grid will create new rows in the implicit grid as required for the items it needs to place.

You can instead give grid-auto-flow a value of column. In this case, Grid will display the items as a column, filling the available rows and creating new columns in the implicit grid as required (Fig 6.3).

.cards {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(2,auto);
}

Code example: http://bkaprt.com/ncl/06-02/

Figure

Fig 6.3: A two-row track grid, with content displayed with grid-auto-flow: column.

As with flex-direction in flexbox, these values are writing-mode-aware.

Grid Auto-Placement

The auto-placement rules in Grid do not stop at enabling the flow direction of grid items. Working with Grid auto-placement can almost feel like a completely different layout model again, if your first impression of Grid is a method to define a grid and then state where you want elements to be placed on it. Many common UI tasks can be achieved with the use of auto-placement, and understanding how it behaves is key to reducing the amount of Grid code you need to write.

Let’s start by playing with the number of tracks auto-placed items can span. The next example is a set of cards, some of which display in portrait mode and others in landscape.

We can lay these out using auto-placement by adding rules to the landscape items, causing them to start on line auto, but end on line span 2 (Fig 6.4). So auto-placement will decide where to put them, but they will always span two tracks.

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    
}
.cards .landscape {
    grid-column: auto / span 2;
}

Code example: http://bkaprt.com/ncl/06-03/

Here, items stay in document source order. When Grid encounters an item that doesn’t fit, it leaves a gap and moves on to the next row. It’s possible to backfill those gaps, however.

We met the grid-auto-flow property earlier in this chapter, when we used it to set the direction of auto-placement to column. This property can also take a keyword of dense or sparse, with sparse the default.

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    grid-auto-flow: dense;
}

If we now look at our example, rather than a gap being left, Card 4 has been moved out of document source order to fill the gap between the second and third cards. Card 6 then appears between Card 3 and Card 5. We end up with a neat grid with no gaps; however, the items are now visually displayed in a different order from the way they are listed in the document source (Fig 6.5).

Figure

Fig 6.4: The items span one column track by default. With a class of .landscape, they span two.

Figure

Fig 6.5: With grid-auto-flow: dense, items are taken out of document source order to fill the gaps.

This behavior can be very handy if you have a collection of elements that lack a logical order. That may be the case for a photo gallery, for example; the images may not need to be displayed in any particular order on the page. Even then, though, you need to take care; with the power of reordering also comes a responsibility to use this feature sensibly, not causing the layout to become burdensome for someone who doesn’t use the web like many of us do.

Changing display order and accessibility

The flexbox and Grid specifications both deal with the issue of accessibility and reordering, and both state that visual reordering does not change the logical order of the document. In practice, this means that the default tab order, for someone navigating around your site with a keyboard, follows the source and not the display. If you reorder the display through auto-placement, or by placing items in an order other than the document order, you could cause someone to jump around the document haphazardly when using the keyboard.

You can see this in our grid-auto-flow: dense example. If you try tabbing from link to link, you’ll see that the tab order follows the order in which the items appear in the source, not in the modified order you can see on screen.

This means you need to take great care whenever you do something that takes elements away from the order in which they exist in the source. You should always consider whether it makes sense also to update the source to maintain the logical order. For an excellent explanation of the problems caused by disconnecting source and visual display, read Léonie Watson’s “Flexbox & the keyboard navigation disconnect” (http://bkaprt.com/ncl/06-04/).

The order Property in Flexbox and Grid

The flexbox and Grid specifications include the order property, which can set an order for flex or Grid items.

Using the order property in flexbox changes the display order of the items.

.cards {
  display: flex;
}
.cards li:nth-child(1) {
  order: 3;
}
.cards li:nth-child(2) {
  order: 1;
}
.cards li:nth-child(3) {
  order: 2;
}

Code example: http://bkaprt.com/ncl/06-05/

You can also use the order property in Grid, although here the use seems less obvious; if you want to define a specific position for an item, one of the methods of placing items might be more appropriate. If you use order, however, it will affect auto-placement, since items are placed in what is described as “order-modified document order” (http://bkaprt.com/ncl/06-06/).

In this example, I have given one item (the very first grid item) an order value of 10. The initial value of order is 0, so all items without an order have an order of 0; since 10 is greater than 0, Item 1 should now appear at the end of the list of items. You can see that auto-placement has honored this order and placed the item last (Fig 6.6).

.cards li:nth-child(1) {
  order: 10;
}

Code example: http://bkaprt.com/ncl/05-06/

As with other reordering, this only changes the visual display order, not the logical order in the document. If tempted to rearrange things in this manner, always ask yourself if you should instead address the logical order by updating the document.

Figure

Fig 6.6: The first item is now placed last.

The Danger of Markup “Flattening”

In this chapter, we’ve looked at some powerful features of our new layout methods—features that enable the moving of elements out of the context in which they sit in the source. This can be helpful, of course, but it represents another area where we need to consider all of our users, not just those who look at our design on screen, and use a mouse or trackpad to navigate.

There is a final consideration to make when developing using flexbox and Grid, and that is to avoid the temptation to flatten out markup to make it easier for elements to become flex or Grid items.

At present, an item only becomes a flex or Grid item if it is a direct child of the flex or Grid container. For example, if you create a grid for some content, then inside the content area is a list ul element—the list items inside that element will not become grid items. The ul itself could become a grid container—but it wouldn’t relate to the outer grid; it would be a new nested grid. It might be tempting to decide that the list doesn’t really need to be a list at all; if it were just a set of div elements, they would all be direct children and sit nicely on our grid. Be careful, though—that way danger lies!

Make good decisions for your source and then work out how to manage the visual display of items, even if that requires a little more work at the outset.

subgrid

The CSS Working Group is discussing a feature that might be a solution for this issue: subgrid, which would cascade the outer grid down to the children of a grid item, allowing our list items to participate in the same layout as their ul. While this feature was included in the Level 1 specification, it has recently been moved to Level 2. The initial spec for the feature has not yet been implemented in any browsers and the CSS Working Group felt it required extra discussion, now that people are starting to use Grid Layout. Many of us hope that this powerful feature will make its way through the discussions and be implemented very soon.

display: contents

While we wait for subgrid, a new value of the display property can give us some ability to allow indirect children to participate in our flex or Grid layouts. In the CSS Display specification, the value of contents is described thus (http://bkaprt.com/ncl/06-07/):

The element itself does not generate any boxes, but its children and pseudo-elements still generate boxes as normal. For the purposes of box generation and layout, the element must be treated as if it had been replaced with its children and pseudo-elements in the document tree.

If we take the example of a ul as described earlier, we can see how this works. In my next example, I have a grid; one of the direct children of my grid is an unordered list element. The list items inside that ul don’t participate in Grid Layout, so they display one beneath the other (Fig 6.7).

.cards {
  display: grid;
  grid-gap: 20px 10px;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
        }
.cards > * {
  background-color: #edf2ff;
  border: 1px solid #bac8ff;            
  padding: 10px;
  border-radius: 5px;  
}
.cards ul {
  list-style: none;
  margin: 0;
}
.cards li {
  background-color: #bac8ff;
  border:1px solid #fff;
}
<div class="cards">
  <div>
    <h2>Card 1</h2>
  </div>
  <div>
    <h2>Card 2</h2>
  </div>
  <div>
     <h2>Card 3</h2>
   </div>
   <ul>
     <li>List item 1</li>
    <li>List item 2</li>
    <li>List item 3</li>
  </ul>
</div>

Figure

Fig 6.7: The items lay out on the grid. The subitems of the ul are not part of the grid layout.

If we then add display: contents to the rules for the ul, the boxes generated by the ul disappear and the li items now lay out on the grid (Fig 6.8).

.cards ul {
  list-style: none;
  margin: 0;
  display: contents;
}

Code example: http://bkaprt.com/ncl/06-08/

Figure

Fig 6.8: The box for the ul has disappeared; the li elements now become part of the grid.

Note, however, that they don’t take on the other styling of the direct children—only box generation is affected by display: contents.

Judicious use of this value can help prevent markup flattening and allow you to make items deeper in the markup part of a flex or Grid layout. You probably won’t want to use it everywhere, since it limits elements to being part of a very specific structure—nonetheless, it’s a very useful trick to have up your sleeve.

I hope this chapter has both excited you about some of the possibilities of our new layout methods and given you food for thought about their accessibility. In Chapter 7, we’ll explore how we can start to use these newer methods, given that some browsers don’t yet support them.

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

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