Creating Multi-column Layouts Without Floats or Positioning CSS3

The flexible box layout model introduces a dedicated system for creating multi-column and multi-row layouts that works very differently than floats or absolute positioning. It’s easiest to see how the flexible box model works with real examples and open the file flexbox_start.html in your code editor.

Each of the divs stacks vertically down the page, as do all block-level elements by default . We can use flexible box layout to make them display horizontally instead.

Without using float, the divs stack vertically down the page.

Without using float, the divs stack vertically down the page.

The first step to making blocks sit next to each other horizontally is to set the display value of their container to box—a new value in CSS3 for the familiar old display property. A div named content is the container for the two main columns, the content-main and content-secondary divs; this wrapper div was not present, but we have added it here because it’s necessary for using flexible box layout. In the styles in the head of the page, add a new rule for #content to match the following:


Setting display to box turns the div into what the W3C calls a flexible box, or often simply box, and tells the browser that you want to switch to the flexible box model for this div and its children. Firefox and Webkit-based browsers—the only browsers that currently support the flexible box layout model—support the values -moz-box and -webkitbox, respectively. Right now, no browser supports the non-prefixed box value, and Opera doesn’t yet support -o-box, but we’ve added these properties for future compatibility.

EXTRA WRAPPER divs
The fact that we had to add an extra wrapper div around the contentmain and content-secondary divs illustrates one of the disadvantages inherent in the flexible box model: it requires extra nesting of divs that float-based layouts often don’t need. You always have to have that outer div to set to display: box before you can turn the inner div into columns. A few extra wrapper divs is not a huge problem, especially given the advantages of simplified CSS and broadened layout options that the flexible box model offers, but it’s worth mentioning—we believe in full disclosure here!

Next, tell the browser that you want to lay out the child elements horizontally by using the box-orient property, along with the browserspecific equivalents:

When you set display to box, the browser automatically sets boxorient to inline-axis, which, in languages like English that run horizontally, does the same thing as a value of horizontal does:
it lays out the blocks side by side instead of top to bottom. So, technically, we don’t need to include the box-orient property here— the boxes would be horizontal without it. But we’ve included it here in the interest of clarity, so you can see how to use this new property.

Adding this rule makes the page change dramatically in appearance; the content-main and content-secondary divs are now sitting side by side, but you can hardly tell it because each has grown to a ridiculous width—so wide, in fact, that you can’t even see any of the secondary content in the viewport in this example. Instead, you see an extensive horizontal scrollbar in the browser .

The two content divs are now placed side by side, but overflow tremendously off the right side of the viewport.

The two content divs are now placed side by side, but overflow tremendously off the right side of the viewport.

This happens because children of flexible boxes are made as wide as needed for their content; this is called intrinsic sizing, similar to how floats without widths are sized. The longest sentence or widest image in the div determines its width. In many cases, this would be a desirable thing, but not in the case of our content divs. To overcome this, you can either give each div a width or max-width, or you can make one or both of the divs flexible using the box-flex property.

Making Blocks Flex
The box-flex property doesn’t actually stop the child divs from being sized intrinsically, but it does force the content within them to wrap so they don’t push their container wider than 100 percent width. It makes the divs adjust their width flexibly to the width of their container.

If the total of the children’s intrinsic widths is less than the width of the container, the children increase in width to fill the extra space. If the total of the intrinsic widths is more than the width of the container, the children decrease in width.

The amount they increase or decrease by is a proportion of their intrinsic widths, not an absolute value. Flexible blocks also flex in proportion to each other. For instance, a block with a box-flex value of 2 is twice as flexible as a block with a box-flex value of 1—the extra space would be doled out to the blocks in a two-to-one ratio.

This is easiest to see with real examples. Figure below shows a gray 800-pixel-wide box holding two inflexible divs at their intrinsic sizes; at the text size shown, the yellow div is 99 pixels wide and the pink div is 493 pixels wide. That leaves 208 extra pixels of space inside the box. If you set the box-flex value to 1 on both divs, they would divide up the 208 pixels of extra space in a one-to-one ratio— in other words, they’d split it evenly . But if you gave the pink div box-flex: 2, it would get twice as much of the extra space as the yellow div gets .

The yellow and pink divs are both sized only as large as their content, leaving extra space within their gray container div.

The yellow and pink divs are both sized only as large as their content, leaving extra space within their gray container div.

Both divs have 104 pixels of space added on to them.

Both divs have 104 pixels of space added on to them.

Out of the 208 extra pixels, the pink div gets 139 pixels added on to it, while the yellow one gets only 69 pixels added, since their box-flex values are in a two-to-one ratio.

Out of the 208 extra pixels, the pink div gets 139 pixels added on to it, while the yellow one gets only 69 pixels added, since their box-flex values are in a two-to-one ratio.

It works the same way when the blocks are too wide for their parent box—the overage of space just gets subtracted from each block in the ratio set by the box-flex values. For instance, in Figures below, the widths of the containing boxes have been reduced to 500 pixels wide, less than the total of the intrinsic widths of the child divs.

In, both children divs have box-flex: 1, so both are shrunk by 46 pixels. In Figure below, the pink div has box-flex: 2, so it gets shrunk twice as much as the yellow div.

Both divs have 46 pixels subtracted from their widths in order to fit in the 500-pixel-wide box.

Both divs have 46 pixels subtracted from their widths in order to fit in the 500-pixel-wide box.

The pink div has 61 pixels subtracted from it, while the yellow one has only 31 pixels subtracted, since their box-flex values are in a two-to-one ratio.

The pink div has 61 pixels subtracted from it, while the yellow one has only 31 pixels subtracted, since their box-flex values are in a two-to-one ratio.

In our page, let’s first try making both the content-main and contentsecondary divs equally flexible by setting box-flex to 1 in the existing #content-main and

#content-secondary rules:

Now both divs are constrained within the wrapper div (Figure below).
But Firefox and Webkit-based browsers decide differently how large to make each content div; Figure below shows the layout in Firefox,

it in Chrome, both at the same viewport width. I don’t know which of these is correct—or even if either is technically wrong, as the W3C spec may not provide enough detail on how the browser should determine an element’s intrinsic size.

The two content columns being sized intrinsically by Firefox.

The two content columns being sized intrinsically by Firefox.

The two content columns being sized intrinsically by Chrome; note how much larger the sidebar is than in Firefox.

The two content columns being sized intrinsically by Chrome; note how much larger the sidebar is than in Firefox

Regardless, it’s clear that in this case, setting both of the content divs to be flexible is not going to work for our design. Instead, let’s give the sidebar an explicit width, as well as a left margin to create some space between it and the main content column:

Now the sidebar will always be 16 ems wide and the main content column will flex to fill whatever space is left after the sidebar and its margins have been accounted for . This works even if the overall layout isn’t liquid to adjust to the viewport; if the wrapper div was set to 960 pixels wide, for instance, the sidebar would take up 16 ems of that, and then the main content column would take up the remaining number of pixels. The “flex” part of the box-flex property refers to the block’s ability to flex in order to fill whatever space is available in its parent box—even if that parent is fixed-width—not necessarily to flex to fill the viewport.

The sidebar is now 16 ems wide, leaving the rest of the width for the main content column.

The sidebar is now 16 ems wide, leaving the rest of the width for the main content column

Adding Columns
This layout illustrates one of the advantages of the flexible box model: you can easily combine elements of different units side by side. The main content column is in percentages (implicitly), the margin in pixels, and the sidebar in ems. This type of hybrid layout is possible without flexible box layout, but it’s more difficult and messy.

Using flexible box layout, on the other hand, made creating this twocolumn hybrid layout pretty simple. Here’s all it took:
1. Set the display of the container of the columns to box.
2. Set the box-orient of the container to horizontal.
3. Give the sidebar a width.
4. Make the main content column fill the rest of the space using box-flex.

If you had more columns, you could give those widths as well, or make them flex to the space available using box-flex. You wouldn’t need to readjust all the widths and margins to make room for the extra columns—everything adjusts automatically.

To see this in action, let’s add another column to the footer. First, we need to put the existing two divs in the footer into the same twocolumn layout as the two content divs are in. Add the display and box-orient properties to the existing #footer rule:


Next, add these new rules for the divs within the footer:

And just like that, we have a two-column layout in the footer.
Changing it into a three-column layout is just as simple. First, add the third div in between the about and credits divs. Copy and paste the following HTML from the file flex-box_2.html from the exercise filesr:

Now, add a rule for the learn-more div, setting its width and margins:

Without making any other changes to the CSS, the footer now has a three-column layout instead of two . We didn’t need to adjust the widths or margins of the about or credits divs; since the about div had been set to flex, it automatically shrank to make room for the new third column. Again, this would happen just the same if the wrapper were a fixed pixel width instead of a liquid width that adjusts to the viewport.

The about div automatically flexes to decrease in width to make room for the new learn-more div.

The about div automatically flexes to decrease in width to make room for the new learn-more div.

This ability to add and remove columns easily without having to change dimensions of surrounding elements can make your CSS cleaner and easier to develop in a number of real scenarios. For instance, your site may have a news sidebar that shows on only certain pages, such as the home page, Newsroom, and About Us sections of the site. The two-column pages and the three-column pages that include the news sidebar can all be coded identically, save for the addition of the news div in the HTML, because the other divs in the page will automatically adjust to make room for it if it’s there. You don’t have to create separate CSS rules for the two- and three-column versions of all the divs in the page, like this:.


Reordering Columns

Another benefit of using flexible box layout is that it’s easy to visually reorder columns without having to touch the HTML. There are a couple properties that will help you do this.

The simpler of these properties is the box-direction property.
If you want the sidebar to be on the left instead of the right, for instance, set box-direction to reverse in the #content rule, and change the left margin on the sidebar to a right margin:

This makes the browser lay out the divs horizontally, starting on the right side instead of the left. Since the content-main div comes first in the HTML, the browser starts off with it, placing it on the right side, and then puts the content-secondary div to its left (Figure below). If the divs were stacked vertically instead of horizontally, setting boxdirection to reverse would make them stack from bottom to top instead of top to bottom.

Setting box-direction to reverse places the first div in the HTML, the content-main div, on the right side of the page.

Setting box-direction to reverse places the first div in the HTML, the content-main div, on the right side of the page.

For more control over where each block is placed, you can use the box-ordinal-group property to assign a placement order. The blocks with a box-ordinal-group value of 1 are placed first, then the ones with a value of 2, and so forth. This means that if you wanted the learn-more div in the footer to be placed on the far left instead of in the middle, you set the box-ordinal-group values on the three footer children divs accordingly:

Also, switch the learn-more div’s left margin over to the right:

Since the learn-more div now has a lower box-ordinal-group value than its sibling divs, the browser places it first. And because we’ve told it to place the boxes from left to right (the box-orient is horizontal and the box-direction is implicitly normal on the footer), that puts the learn-more div on the far left . The browser then places the about and credits divs to the right. Since these divs both have the same box-ordinal-group value, the browser decides which of the two to place first by looking at the source order: boxes that come first in the source get placed first, as you’re used to with normal boxes in the flow of the page.

Even though the learn-more div comes in between the about and credits divs in the HTML, its box-ordinal-group value lets the browser place it on the far-left side of the page.

Even though the learn-more div comes in between the about and credits divs in the HTML, its box-ordinal-group value lets the browser place it on the far-left side of the page.

Being able to control the visual placement of blocks in a layout without regard for the source order is incredibly powerful. It lets you put the most important content first in the HTML, even if you don’t want that content to display first visually, which helps the page degrade well in assistive technology, linearize well in devices without CSS support, and perform better in search engines.

Equal-height Columns
Another nice benefit of flexible box layout—though a more trivial one—is that creating equal-height columns is dead easy.

Many designers from the pre-CSS days (like me) got used to being able to easily create equal-height columns using tables. Cells in the same table row automatically expand to the same height, but individual divs that just so happen to display side by side have no reason to do this. In a quest to get div-based columns in a layout to appear to be equal in height, designers and developers came up with many clever but hacky CSS solutions. These equal-height column techniques might involve one or more extra wrapper divs, background images (even when all you wanted was a solid background color, or no background at all but just a border), and relatively complicated CSS.

Using flexible box layout for equal-height columns still requires a wrapper div, but it doesn’t take any images (helping your pages load faster by saving HTTP requests), and it uses very simple CSS. All you have to do is set the box-align property to stretch on the flexible box, which is the parent of the columns. This is the default value of the boxalign property, so you can see it working in our example page simply by setting background colors on the two main content columns:

Save the page and view it in Firefox, Safari, or Chrome. The pink background of the sidebar stretches down to the end of the gray background of the much-longer main content column .

The two content divs stretch to the same height, because the children of boxes are given a box-align value of stretch by default.

The two content divs stretch to the same height, because the children of boxes are given a box-align value of stretch by default

Again, this happens because boxes by default have box-align set to stretch; we’d get the same effect if we added it explicitly to the #content rule, like this:

The box-align property controls how a box’s children are aligned relative to each other perpendicularly to the box’s orientation. So if the box’s children are being laid out horizontally, as in our example, box-align controls the vertical alignment; if our blocks were stacked vertically, box-align would control their horizontal alignment.

The possible values for box-align are described in Table below. Note that the definitions for start and end are the opposite for reverse-direction boxes; for instance, horizontal blocks that are reversed and have a boxalign value of start should be aligned on the bottom, not the top as usual. However, browsers don’t currently follow this.

box-align values

box-align values

Vertical and Horizontal Centering
The box-align property not only makes equal-height columns possible, but it also means that vertical centering—one of the hardest effects to accomplish with CSS 2.1—is now an easy feat, even when both the parent box and child block have unknown heights. In addition, another new property named box-pack makes horizontal centering in traditionally tricky situations really simple too.

Let’s try out both types of centering in the header area of our page. We have e changed the HTML markup for this area slightly: now the header div wraps around the logo image and search form, and the nav-main div is separate.

VERTICALLY CENTERING THE LOGO AND SEARCH FORM
Having a wrapper around only the logo and form makes it possible to vertically center these two elements in relation to each other.

First, make the header div into a flexible box by setting its display to box:


As explained earlier, children of flexible boxes will display horizontally by default, without setting the box-orient property, so this CSS change alone puts the logo and search form on the same line

Now that the logo and the search form are children of a flexible box, they sit side by side.

Now that the logo and the search form are children of a flexible box, they sit side by side.

To get the search form to display on the right side of the screen instead of up against the logo, you need to tell it to stretch to fill the rest of the space left over after the logo. You also need to set textalign to right to move the content within the form to its right side.

Add a new rule for #form-search to do both of these things:

Now the search form is over on the right where we want it in Safari and Chrome (Figure below). But in Firefox, it hasn’t budged. This is because Firefox is sizing the header div intrinsically, making it only as wide as its content. This behavior is correct for children of boxes, but Firefox should not be doing it to the box itself. But it’s easy to fix—just set the width of the header div to 100 percent:

In Webkitbased browsers, the search form now flexes to fill all the space to the right of the logo, and the content within the form is aligned to the right.

In Webkitbased browsers, the search form now flexes to fill all the space to the right of the logo, and the content within the form is aligned to the right

This makes Firefox stop shrinkwrapping the header and instead stretch it out to fill the full width of the wrapper div. Now the search form is on the right side of the screen in Firefox as well as in Webkitbased browsers.

Now that the logo and form are in the right spots horizontally, let’s move them to the vertical spots we want. All you have to do is set boxalign to center on the

And with that, the logo and search form are aligned in the middle with each other and vertically centered within the header div (Figure below). No matter how large the font size for the form grows, or if the elements of it wrap onto two lines, it will always adjust and stay vertically centered.

Setting box-align to center on the header div vertically centers the logo and search form.

Setting box-align to center on the header div vertically centers the logo and search form.

HORIZONTALLY CENTERING THE NAV BAR

Now we can turn our attention to the next item on the page, the nav bar. To center it horizontally in the wrapper div, setting box-align to center won’t work—remember that it applies only to the vertical space around horizontal boxes (and vice versa for vertical boxes). We need a property that affects the extra space in the same axis as the blocks—in this case, horizontal.

This is exactly what the box-pack property does. We can use it to move the ul element into the center of the nav-main div. To do so, first turn the nav-main div into a box and set its box-pack value to center.

Make these changes to the existing #nav-main rule:

Next, you need to make a couple changes for Firefox’s sake. Add width: 100% to make the div stretch to fill its container. Also, remove the overflow: auto declaration to fix a Firefox bug that would cause the nav-main div to disappear:

If you save your page and view it in Firefox, Safari, or Chrome now, you’ll see that the nav bar is indeed horizontally centered within the page . Setting box-pack to center tells the browser to take whatever extra horizontal space is left over within the nav-main div and divide it equally on either side of the ul block within it.

Setting box-pack to center on the nav-main div horizontally centers the nav bar.

Setting box-pack to center on the nav-main div horizontally centers the nav bar.

All of the possible values for box-pack are described in Table below.
Remember, as with box-align, the definitions for start and end are the opposite for reverse-direction boxes. Firefox does follow this, but Webkit-based browsers do not.

box-pack values

box-pack values

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

CSS3 Topics