Styling your application¶
Styling and layout is a thorny issue for programmers. Reahl provides some support for dealing with this issue – but we can probably do a whole lot more. Here is what we’ve got currently.
Complex Widgets in Reahl are written such that the Widget has an identifiable HTML element that represents the Widget. Identifiable means that the HTML element has an id or class attribute which can be used as target of CSS selectors. This allows for CSS to be attached to each Widget (or its contents). For example, the TabbedPanel is in a <div class=”reahl-tabbedpanel”>. Widgets that map one-to-one to HTML tags do not have special classes – they can be targeted in CSS by just using the HTML tag name they represent: the reahl.web.ui.P Widget is just a <p>, for example.
Given these ways to be able to target a Widget via CSS, you can write normal CSS to provide your own look and feel for Reahl Widgets (if you really want to). In the reference documentation for each Widget, an explanation is given of what the HTML for that Widget looks like, for this purpose.
However, what Widgets look like is probably not the first thing on a programmer’s mind. It is useful just to start programming using some look for the Widgets, and later customise this look to your liking. For this reason, a stylesheet is provided which includes styling for all the standard Reahl Widgets. You can include this style by adding it to the Head of your HTML5Page:
If you are using the TwoColumnPage as a page, the same effect can be accomplished by merely passing style='basic' to its constructor (as can be seen in almost all of our code examples so far).
Positioning of elements on a page can be quite tricky, given how the implementors of different browsers bend the specifications to their will. To deal with this issue in a browser-agnostic way, Reahl uses the YUI 2 Grids CSS framework.
The YUI 2 Grids CSS framework does the following things:
- It resets all fonts to look the same on all browsers
- It resets all margins, padding, of elements etc to 0 (to ensure these settings are the same on all browsers)
- It includes CSS that makes positioning things in a layout grid using YuiGrid and YuiUnit container Widgets.
To develop your own page, you need to understand how YUI 2 Grids CSS works. Then use basic Reahl Widgets to build your own HTML5Page-derived page that will provide the structure you need. The TwoColumnPage Widget is an example of how one can do this.
A TwoColumnPage is a basic page which contains a header area, footer area and two columns: a smaller one to the left and a larger one to the right of the page. The header area spans the top of the two columns, and the footer spans the area below the two columns. All the user of a TwoColumnPage needs to know is what Slots the TwoColumnPage provides, or what elements it has to which you could add more children.
As an example of how you could build your own, here is the implementation of TwoColumnPage, that shows how Yui elements are used to construct a page layout:
class TwoColumnPage(HTML5Page): """An HTML5Page with a basic layout: It has a header area which displays at top of two columns. A footer area displays below the two columns. The main column is to the right, and larger. The secondary column is to the left, and smaller. .. admonition:: Styling Renders as a page structured using `Yui 2, with two template preset columns <http://developer.yahoo.com/yui/grids/#start>`_ (main and secondary). The TwoColumnPage has the following Slots: main Used by Views to plug content into the main column. secondary Used by Views to plug content into the secondary column. header Used by Views to plug content into the header area. footer Used by Views to plug content into the footer area. :param view: (See :class:`reahl.web.fw.Widget`) :param title: Text for a template to be used as document Title (See also :class:`Title`). :param style: (See :class:`reahl.web.ui.HTML5Page`) :param css_id: (See :class:`HTMLElement`) """ @arg_checks(title=IsInstance(six.string_types)) def __init__(self, view, title='$current_title', style=None, css_id=None): super(TwoColumnPage, self).__init__(view, title=title, style=style, css_id=css_id) self.yui_page = self.body.add_child(YuiDoc(view, 'doc', 'yui-t2')) self.main.add_child(Slot(view, 'main')) self.secondary.add_child(Slot(view, 'secondary')) self.header.add_child(Slot(view, 'header')) self.footer.add_child(Slot(view, 'footer')) @property def footer(self): """The Panel used as footer area.""" return self.yui_page.footer @property def header(self): """The Panel used as header area.""" return self.yui_page.header @property def main(self): """The Panel used as main column.""" return self.yui_page.main_block @property def secondary(self): """The Panel used as secondary column.""" return self.yui_page.secondary_block # Uses: reahl/web/reahl.ajaxlink.js
There are also some Widgets with special behaviour that relate to layout and styling:
- This Widget wraps around an Input, and adds a Label to it. The combination of the Input and its Label are then arranged in two columns next to each other. Successive LabelledBlockInputs appear underneath each other, with all the Labels aligned and all the Inputs aligned.
- A LabelledInlineInput also wraps around an Input and adds a Label. The result though is an element that flows with text and can be used as part of a paragraph (reahl.web.ui.P), for example.
Sometimes it is useful to visually highlight certain Widgets to make them stand out amongst their peers. This concept is called the “priority” of a Widget. Normally, you would not specify the priority of a Widget. But, amongst chosen grouping of Widgets, you may set one Widget as having “primary” priority, with the others having “secondary” priority.
A Widget with “secondary” priority will have a CSS class reahl-priority-secondary attached to it, which is normally styled such that it fades a bit into the background (perhaps lighter, or slightly greyed out). A Widget with “primary” priority will have CSS class reahl-priority-primary which is normally styled such that it stands out visually.
The PriorityGroup is an object to which you can add Widgets, stating their priority (or lack of it). The PriorityGroup will ensure that only one of the Widgets added to it will ever have primary priority. (Many could have no priority set, and many could be secondary.)