{% raw %} # Consistency rules These are hard, structural rules, not suggestions. They are derived from the **posts / feed page**, which is the reference implementation: structurally and visually it is the most correct page in the application. Other pages will be refactored to match it; when a new page is built, it follows these rules from the start. The point of the rules is that the header, breadcrumb, content root, and footer are *shared infrastructure*. A page supplies its content and its stylesheet; it never rebuilds the frame. ## The reference skeleton This is the shape of the posts page, reduced to its structure. A content page looks like this and nothing else: ```html {% extends "base.html" %} {% block extra_head %} <link rel="stylesheet" href="/static/css/feed.css"> {% endblock %} {% block content %} <h1 class="sr-only">Feed</h1> <div class="feed-layout"> {# exactly one layout container #} <aside class="sidebar-card"> ... </aside> <div class="feed-main"> ... </div> <aside class="feed-right"> ... </aside> </div> {% endblock %} ``` The header, breadcrumb, `
` wrapper, and footer are all supplied by `base.html`. The template above never appears to contain them, and never should. ## Hard rules ### 1. Extend the base template Every page is `{% extends "base.html" %}`. Page CSS is added only through `{% block extra_head %}`; page JS only through `{% block extra_js %}`. A page never includes its own ``, ``, or ``, and never links `variables.css` / `base.css` / `components.css` (the base already does). ### 2. The header is shared, never re-implemented The top nav is `base.html`'s `.topnav`. Pages do not build their own header or navigation bar. The active link is derived from the request path inside `base.html`. If a page needs a page-level toolbar (tabs, filters), that toolbar lives *inside the content*, like the feed's `.feed-nav` strip, below the breadcrumb, not as a second site header. ### 3. Breadcrumbs are mandatory (this is the most-broken rule) A page **must** pass at least two breadcrumbs (Home plus the current page) through its SEO context: ```python seo_ctx = list_page_seo( request, title="Projects", breadcrumbs=[{"name": "Home", "url": "/feed"}, {"name": "Projects", "url": "/projects"}], ) ``` This is not only for SEO. The `.breadcrumb` element carries `padding-top: calc(var(--nav-height) + 0.5rem)`, and that padding is **what pushes the content clear of the fixed top nav**. A page that ships no breadcrumbs (or only one) has its first content hidden behind the header. Always supply two or more. ### 4. All content lives in the single content root `base.html` already wraps the `content` block in `
` (`max-width: 1200px`, centred, `padding: 1rem`). Therefore a page: - puts everything inside one top-level layout container (a grid like `.feed-layout`, or a single column); - never adds a second centred / `max-width` wrapper inside `.page`; - never re-declares the maximum content width. See [Layout](/docs/styles-layout.html) for the approved layout containers. ### 5. Multi-column structure is grid, and it collapses Side columns are `
Anatomy of a page (what base.html owns vs what the page supplies)
DevPlace · Home Posts News Gists Projectsbase.html: .topnav (fixed)
Home / Projectsbase.html: .breadcrumb (clears the nav)
Your content, inside one layout container.page: block content, inside .page
DevPlace · footer linksbase.html: .site-footer