Chapter 4, Flexbox and Float

This reading summarizes and expands on the concepts of responsive and flexible layouts that we learned in chapter 4.

If you don't have Chapter 3, here's a link to a copy of a scan of the chapter. To respect the author's copyright, the link is only valid on-campus or with a password. Ask Scott if you don't have that password.

FEWD Chapter 4

Mobile First

We should first design our websites so that they work effectively on small devices, and only later take advantage of greater space. Some rules of thumb:

  • don't lay things out horizontally; stack things vertically
  • give images CSS declarations like width:100% so that they scale to smaller displays
  • don't use table elements and such that might be wider than the display
  • specify widths in percentages when feasible
  • don't specify widths of elements in pixels (or, at least, wide widths) which might result in the dreaded horizontal scrolling

inline-blocks

In the last chapter, we learned about inline elements, like span, that are found in running text and would move around as the browser gets wider and narrower.

We also learned about block elements, which use the box model, can (typically) contain other block elements, and stack vertically on the page.

We now know about inline block elements, achieved with display:inline-block. Such elements act like inline elements in terms of filling out the width of their container (moving other inline elements up from the next line until there's no more space), but they act like block elements in that they can contain other block elements.

Note that the default width of a block or inline-block element is 100%, which means that there is never any room left to bring another one up from the next line. So, it only makes sense to use inline-block where you are setting the width (or it's a replaced element, like an img, and so the width is derived from the contents). Like this:

selector {
    display: inline-block;
    width: 20%;  /* five on a line */
    ...
}

New HTML

  • main The main content of a page. Bigger than an article
  • div A meaningless block container. Useful for structuring the page

Flexbox

With Flexbox, there is

  • a container that is limited in size. Presumably takes the whole screen or a portion thereof. Get these with display:flex. Contrast that with a Wikipedia page that is as long as it needs to be
  • a set of flex-items to be displayed, all children of the container. This is automatic.
  • a direction or main axis that the children will be oriented in (horizontally or vertically)
  • a cross axis that is perpendicular to the main axis
  • a specification for what happens with any leftover space in the flex container

Flex containers can be nested, so you have have rows with columns, columns within rows, even rows within rows and columns within columns.

Flex items can grow and shrink. We learned two uses of the flex shorthand property:

  • flex: 0 1 auto means don't grow me, shrink me if needed, and calculate my size from my contents
  • flex: 1 1 auto means grow me as much as possible, shrink me if needed, and calculate my size from my contents

Flexbox Simplified

I really like our book's example of flexbox in Ottergram, because it shows how sophisticated and powerful it can be. But it's a tough place to start. I strongly urge you to start with a simple case. The simple cases have at least the following features:

  • a parent element and two or more children
  • the parent will set the following:
    • display:flex which is what makes it a flex parent
    • flex-direction which determines whether the children are in a row or a column
  • each child (flex-item) can (optionally) set
    • flex: grow shrink basis

So, at minimum, you need two CSS properties on the flex parent to use the flexbox feature. (Actually, there's probably a default for flex-direction, but let's not.)

Take a few minutes to look at these flex examples

New CSS Properties

Pretty much all of these are related to the new flexbox layout

  • display:flex to specify that an element is a flex container/parent.
  • flex-direction row or column
  • flex how a flex item (child) shrinks or grows
  • align-items aligning (e.g. centering or stretching) flex-items. If the item doesn't fill the space allocated to it, where does it end up in that space. See more at MDN align-items
  • justify-content what happens with leftover space in a flex container?
  • overflow set what happens when an element's contents is bigger than it is. Scroll? Hide? Show?
  • order what order does this flexitem go in? source order? after others? before others? contents is bigger than it is. Scroll? Hide? Show?
  • text-shadow can add a shadow to some text by reprinting the text in a different color and a small displacement
  • white-space what happens with white space in an element: normal? nowrap?

Absolute and Relative Positioning

Normally, we let the browser figure out where an element should land on the page, based on its size, the size of the container, whether it's a block or inline element, and so forth. This is because the default value of the position CSS property is static. It has two other interesting values:

  • position:relative which allows you to shift the element from its static position
  • position:absolute which allows you to place the element within a Cartesian coordinate system

Here's a sentence in which a single red word has been moved from its usual place. Of course, we could use that class again, to raise another word out of its place.

Here's how that's done. First, the CSS:

.up_and_right {
    position: relative;
    top: -1em;
    left: 2em;
    color:red;
}

Here's the HTML:

<p>Here's a sentence in which a single red <span
class="up_and_right">word</span> has been moved from its usual
place. Of course, we could use that class again, to raise another word
out of <span class="up_and_right">its</span> place. </p> 

In general:

  • The element is shifted vertically using either top or bottom and giving a signed distance by which to move the top or bottom of the element.
  • It's shifted horizontally using either left or right and another signed distance.
  • The starting location is where it would have been if it had been position:static (the default) rather than position:relative.
  • Note that other elements don't move as a result of the movement of this one. (There's a gap left in the sentence above, where the word was moved from.) The moved element can even overlap other elements; that can't happen with float.

You might wonder why subtracting 1em from the top causes the word to move up. That's because the coordinate system for absolute and relative is a little different from the x,y Cartesian coordinate systems you learned in middle school or high school:

  • left increases as you go left-to-right, just like x does,
  • top increases as you go down, unlike y which decreases as you go down.

The reason for this weird coordinate system is that the beginning of the document is the main origin, and the beginning of the document is at the top of the page.

Position absolute is similar to position relative, except that the distances are measured not from the element's static position but in an absolute coordinate system, where the origin of the system is the first non-static ancestor and if no non-static ancestor is found, the browser window.

That last sentence is a little weird, so let's rephrase it to give us another chance to understand it. Suppose the element that we want to place is D (for "descendant"). Consider the whole chain of ancestors that D has, all the way up to the body. If any of those ancestors, call it A, has position:relative (or anything other than the default which is position:static) then D is placed relative to A. That is, A sets the coordinate system. If there is no such ancestor, then D is placed with respect to the browser window.

Positioning on a Grid

Therefore, another use of position:relative is to set the coordinate system for its descendants. I like to think of this as "my descendants are positioned relative to me". Here's an example. Each of the colored boxes is 100x100 px. The outer green box is 600px wide by 200px high.

pink child
green child
blue child

This is done by:

  • putting position:relative on the ancestor (here the box with gray background)
  • putting position:absolute; top:100px; left:50px on the pink child
  • putting position:absolute; top:0px; left:-50px on the green child
  • putting position:absolute; bottom:50px; right:100px on the purplish child

Use this feature sparingly. Sites where everything is positioned in absolute coordinates are incredibly inflexible. You want a site that is responsive to the size of the browser. Nevertheless, sometimes position:absolute can be useful.

Note that with position:static, elements can never overlap. In particular, text can't overlap. But with position:absolute and position:relative you can do that, if you want.

Positioning Checklist

It's easy to get confused about the CSS properties you need to use absolute positioning. Here is a checklist:

  • put position:relative on the desired ancestor
  • put position:absolute on the element you want to position
  • set two coordinates on the element you want to position.

The coordinates are usually top and left but they don't have to be. You need to have:

  • exactly one horizontal coordinate, either left or right
  • exactly one vertical coordinate, either top or bottom

Flexbox versus Float

Flexbox is relatively new (circa 2014, though proposals go all the way back to 2009). Prior to widespread support for flexbox, web developers used float, which still has some useful features and is still worth knowing about.

Here's a simple example of float, where we get the text to wrap around an image:

Hermione Granger Hermione Granger was indispensable in the Harry Potter series. Harry had the title role, and he was clearly critical to the story, but he did not have exceptional magical skill. His nemesis, Lord Voldemort, was an extraordinary wizard, matched only by Dumbledore. Harry, was good, but no more than good. Hermione, on the other hand, was "the brightest witch of her age" according to Remus Lupin. There was no spell she couldn't do, and her cleverness and foresight saved Harry countless times.

Float causes the floated elements to be

  1. Removed from the flow, so that later stuff moves up on the page, and
  2. shoved back into the page, causing block elements to overlap it and inline elements to wrap around it.

The example above shows the idea. Hermione's picture is floated (to the left in this case) and the paragraph text (inline elements) flows around it.

Centering Block Elements and Text

People love centering, particularly novice designers. Centering moves things away from the edges, which makes it feel more comfortable, without having to decide how much to move it. But there are two kinds of centering. There's centering block elements and centering inline elements like text. Let's start with centering text:

Centering Text

Centering text is pretty easy: just specify text-align:center on its parent element (or, in general, some ancestor, since the setting is inherited.)

You should almost never center lines of text in a paragraph. You get ragged edges left and right, which looks ugly. Also, depending on the font, amount of text and the width of the region, the last line may be weirdly short (and centered). Here's a Tolkien quote:

Do not meddle in the affairs of wizards, for they are subtle and quick to anger.

You probably don't want that single word centered on the second line. But that can happen (and all-too-often does) when you center text and don't have complete control over browser-width, font-size, and the like.

Instead, what you probably want is to have normal, left-aligned text in a box that is itself centered. Let's see how to center boxes.

Centering Blocks

Here's an example of a block element (blue background) centered within its container (red border):

Do not meddle in the affairs of wizards, for they are subtle and quick to anger.

Note that, by default, block elements are width:100% which means that they are as wide as their container will let them be. So, by default, centering is not possible, because there's no extra space to center within. Therefore, to center a block element, you usually have to set its width to something smaller than its normal width. The blue block above is 80% of its container. One exception is IMG elements, since they get their width from the actual image, not from the container. However, pictures are often quite wide, so you typically have to scale them down using a width setting anyhow.

The trick to centering a block element is to set its margin-left and margin-right to auto. Auto margins means to take whatever space is leftover in the container and distribute it equally to the two margins.

The example above used a shorthand: margin:10px auto which means the top and bottom margins are 10px and the left and right are auto.

Galleries with Floating Elements

We often want galleries of elements, where there should be as many on a line as will fit, but fewer if necessary, without any horizontal scrolling. One way to do that is by setting display:inline-block and set the width on the gallery elements, which allows you to put arbitrary content in each element, while still having them fill the line like inline elements.

Another way is to use float:left as shown by W3schools Gallery