Layout of pages

The reahl.web.bootstrap.grid module provides tools with which you can control the basic layout of a page. Layout is responsive, meaning that it adapts depending on the size of the device used to view the page.

The basic tools for laying out a page are reahl.web.bootstrap.grid.Container, reahl.web.bootstrap.grid.ColumnLayout and reahl.web.bootstrap.grid.ResponsiveSize.

Containers

Some web sites present all their contents in an area of fixed size, with the entire “content area” itself centered on the browser viewport.

A site with fixed container showing how the contents are centered on the viewport.

On other sites, the contents of the site span the entire width of the viewport instead:

A site with fluid container showing how the contents stretch to fill the viewport.

A Container manages the layout of an HTMLElement and its contents to conform to one of these schemes.

A Container is by default “fixed”, which means its contents will be confined to a fixed-size area that is centered on the viewport. The size of this fixed-size area does change if a browser is resized – but it changes only at fixed intervals and stays centered on the viewport.

When constructing a Container it can be set to be “fluid” in order to make it behave like the second example above where the contents of the HTMLElement will fill the available width.

Different areas of a site may be laid out using different Containers. For example, you might want your pages to have a header and footer that both stretch the entire viewport width, but with a content area inbetween that has a fixed width and is centered.

Bootstrap requires that all Widgets laid out with a ColumnLayout be nested somewhere (no matter how deeply) in another which is laid out by a Container.

Responsive grids

A ColumnLayout is used to turn an HTMLElement such as a Div into one row of an invisible grid with a number of columns inside that one row. The Widgets added as children to a particular column are then positioned inside that (otherwise invisible) column.

When adding a column, you need to specify the size of that column. This is done using a ResponsiveSize. A ResponsiveSize lets you specify how wide the column should be on each possible size of user device. User device sizes (called device classes) can be one of:

  • xs (extra small)
  • sm (small)
  • md (medium)
  • lg (large)
  • xl (extra large)

In the code below, 12 columns of 1/12th the page width are added to a Div. Each column is a Div itself and all have the same text in them. Note that the ResponsiveSize is only set up with a size for medium devices. This means that the columns will be 1/12th of the page on medium (or larger) devices. On devices smaller than medium, each column will expand to the full width with all the columns stacked on top of one another. (On small devices it is better to have to scroll down further to see content than to have to scroll right).

    def add_twelve(self):
        div = Div(self.view).use_layout(ColumnLayout())
        self.body.add_child(div)

        for i in range(1, 13):
            column = div.layout.add_column(ResponsiveSize(md=1))
            column.add_child(P(self.view, text='1/12th on md and larger'))

A ColumnLayout can also be constructed with a list of tuples stating what columns it should have and what each one should be called. In this case, it will add all the specified columns (each a Div itself) to the Div you apply it to and make these available as a dictionary. An example is shown here:

    def add_two(self):
        layout = ColumnLayout(('left', ResponsiveSize(md=4)),
                              ('right', ResponsiveSize(md=8)))

        div = Div(self.view).use_layout(layout)
        self.body.add_child(div)

        div.layout.columns['left'].add_child(P(self.view, text='4/12ths on md and larger'))
        div.layout.columns['right'].add_child(P(self.view, text='8/12ths on md and larger'))

In order to really appreciate the power of ResponsiveSize, you will have to fire up the example and play around with it. The example here includes different Views – this View is the first called “Grid basics”.

Here is a screenshot of what the page looks like:

A screenshot of the page.

See how the layout changes if you change the size of the window when running the example yourself. On displays that are medium sized or larger (with your browser maximised), you will see two rows: one with 12 equal sized columns, and another with two columns that are not equally sized.

As soon as you make the browser window smaller than “md” size, things change: All the columns now stack on top of one another and fill the whole width of the screen to make them more usable on the smaller sized screen.

Laying out a whole page

It is often useful to layout an entire page with a header area at the top, a footer at the bottom, and a content area in between. The content area is also often divided into different columns.

You can layout a page in this fashion by using PageLayout in conjunction with a suitable ColumnLayout to be used for its content area.

The “Page layout” view in our example shows how this works:

class PageLayoutPage(HTML5Page):
    def __init__(self, view):
        super(PageLayoutPage, self).__init__(view)

        column_layout = ColumnLayout(('left', ResponsiveSize(md=4)),
                                     ('right', ResponsiveSize(md=8)))
        self.use_layout(PageLayout(document_layout=Container(), contents_layout=column_layout))

        self.layout.header.add_child(P(view, text='The header'))
        self.layout.footer.add_child(P(view, text='The footer'))

        left = column_layout.columns['left']
        left.add_child(P(view, text='To the left'))

        right = column_layout.columns['right']
        right.add_child(P(view, text='To the right'))

Notice how the same responsive properties hold for such pages too – go ahead and make your browser window smaller on this example.

You can nest the usage of a ColumnLayout inside others (like the columns on this page), thereby creating complex grid structures that resize on all levels.