Ludic Logo
Edit

Layouts

Layouts create a flexible structure for your user interface. The layouts in this module are based on the Every Layout Book. If you haven't read the book, go read it now:

These layouts allow us to create complex user interfaces with minimal CSS which are responsive and readable on all devices. The layouts can be combined together.

All layouts are located in the ludic.catalog.layouts module.

Viewing this page on mobile devices
If you are viewing this page on mobile devices, you won't probably see the layouts examples correctly rendered. You can always switch between desktop mode and mobile if you want to see the difference in rendering.

Ideology

#

In this module, layouts are designed as simple, reusable components that you can easily combine to create responsive, readable, and maintainable user interfaces. Instead of starting from scratch with basic HTML elements and manually writing CSS, you use these layouts as your foundational building blocks. This approach allows you to compose and arrange them in various ways to design your desired user interface, making your code more organized and easier to manage.

A New Way of Thinking About Design

When writing CSS, you might be tempted to apply e.g. specific spacing, colors, or font styles to an HTML element like a button. The idea of using the layout classes here is to define context which determines how an HTML element should be displayed. So for example, we might want to have a couple of buttons on one line, so we wrap them in a Cluster class which inserts a margin between all its children and puts them on one line. In another context, we want to widen a button so that it uses all available space and is displayed like a block element. In that case we use the Stack class.

To illustrate this concept, here is a button wrapped in a Cluster:

Here are the buttons wrapped in a Stack:

Let's see the code:

from ludic.catalog.buttons import Button
from ludic.catalog.layouts import Cluster, Stack

Cluster(Button("In a Cluster"), Button("In a Cluster"))
Stack(Button("In a Stack"), Button("In a Stack"))

Stack

#

In the Stack layout, there's margin inserted between all its children elements, and each child occupies all the available horizontal space. So, essentially, each child stretches out horizontally as much as possible, with margins separating them.

Example

One
Two
Three

Usage

from ludic.catalog.layouts import Stack
from ludic.html import div

Stack(
    div("One"),
    div("Two"),
    div("Three"),
)

Use Cases

  • Separating paragraphs in large texts
  • Creating a list of posts on a blog site
  • Separating menu and body on a page

Box

#

The Box layout adds padding around its content from all directions. This means that there is an equal amount of space between the content and the edges of the box, including the left, right, top, and bottom sides. By default, the Box also includes a border and a background that is not transparent.

Example

Box Content Has Padding From All Directions

Usage

from ludic.catalog.layouts import Box

Box("Content")

Use Cases

  • Creating a page menu or sidebar
  • Making important text stand out on a page
  • Using it to highlight a list of actions (buttons)

Center

#

The Center layout ensures that its content stays centered on the page. It sets a maximum width for this content. If the content's width exceeds this maximum, instead of extending beyond the sides of the page, equal margins are created on both sides to keep the content centered.

Example

One
Two
Three

Usage

from ludic.catalog.layouts import Center, Stack
from ludic.catalog.typography import Paragraph

Center(
    Stack(
        Paragraph("Lorem ipsum"),
        Paragraph("Lorem ipsum"),
    )
)

Use Cases

  • Main content of a web page
  • Ideal layout for blog sites

Cluster

#

The Cluster layout, when applied, adds margin between all of its inline children elements. It arranges all of its children elements on a single line until there is enough space on the page. It's important to note that the cluster layout is not intended to be used for block-level children elements like paragraphs.

Example

One
Two
Three
Four
Five
Six
Seven
Eight
Nine
Ten
Eleven
Twelve
Thirteen
Fourteen
Fifteen
Sixteen
Seventeen
Eighteen
Nineteen
Twenty

Usage

from ludic.catalog.buttons import Button, ButtonPrimary
from ludic.catalog.layouts import Cluster

Cluster(
    Button("Cancel"),
    ButtonPrimary("Save"),
)

Use Cases

  • Groups of elements that differ in length
  • Buttons appearing together at the end of a form
  • A list of tags or keywords
#

The Sidebar layout enables you to have two blocks on a page with equal height but different widths. Typically, the sidebar is narrower than the main content area. If there isn't enough space to display both the sidebar and the main content side by side, the layout adjusts into a stack-like format, where one block is stacked on top of the other.

Example

One
Two
Three
Four
Five

Usage

from ludic.catalog.layouts import Box, Sidebar, Stack, WithSidebar
from ludic.catalog.typography import Paragraph

WithSidebar(
    Sidebar(
       div("My Sidebar"),
    ),
    Stack(
        H1("Content"),
        Paragraph("Lorem ipsum"),
    ),
)

Use Cases

  • A page with menu and content
  • A list of actions next to a form
#

You can also have the sidebar on the right side instead of left.

Example

One
Two
Three
Four
Five

Usage

from ludic.catalog.layouts import Box, Sidebar, Stack, WithSidebar
from ludic.catalog.typography import Paragraph

WithSidebar(
    Stack(
        H1("Content"),
        Paragraph("Lorem ipsum"),
    ),
    Sidebar(
       div("My Sidebar"),
    ),
)

Switcher

#

The Switcher layout ensures that all of its children elements have the same width until there is enough space available to display their content. However, if the layout is placed on a page where there isn't sufficient room, it collapses and switches to a stack-like format for display.

Example

One
Two
Three

Usage

from ludic.catalog.layouts import Switcher
from ludic.html import div

Switcher(
    div("One"),
    div("Two"),
    div("Three"),
)

Use Cases

  • Card components advertising products

Cover

#

The Cover layout consists of a header, content and footer. The header is placed above the content and the footer is placed below. The content is centered both horizontally and vertically.

Example

Header

Title

Footer

Usage

from ludic.catalog.layouts import Cover

Cover(
    div("Header"),
    h1("Title"),
    div("Footer"),
)

Use Cases

  • Introductory page for a website

Grid

#

The Grid layout creates a grid of blocks with equal height and width.

Example

One
Two
Three
Four
Five
Six
Seven
Eight
Nine

Usage

from ludic.catalog.layouts import Grid

Grid(
    div("One"),
    div("Two"),
    div("Three"),
    div("Four"),
    div("Five"),
)

Use Cases

  • Teasers for permalinks or products

Frame

#

The Frame layout maintains aspect ratio even if it means the content needs to be cropped.

Example

Frame Content

Usage

from ludic.catalog.layouts import Frame
from ludic.html import img

Frame(
    img(src="/path/to/image", alt="my image"),
)

Use Cases

  • cropping media (videos and images) to a desired aspect ratio

Complex Example

#

You are free to combine layouts and components together. The following is an example of a complex layout consisting of multiple nested layouts mentioned in this tutorial.

Open Layout In New Tab

Slightly modified code of the layout is shown below.

Center(
    Stack(
        Box(
            Cluster(
                b("Inverse Boxed Cluster Menu"),
                Cluster(
                    Button("Item 1"),
                    ...
                ),
                classes=["justify-space-between"],
            ),
            classes=["invert"],
        ),
        WithSidebar(
            Stack(
                H2("Stack", anchor=False),
                Paragraph(...),
                H3("Switcher", anchor=False),
                Switcher(
                    Box("Switcher Item 1"),
                    ...
                ),
                H3("Cluster In a Box", anchor=False),
                Box(
                    Cluster(
                        ButtonPrimary("Cluster Button 1"),
                        ...,
                    ),
                ),
                H3("Grid Advertisement", anchor=False),
                Grid(Box(...), ...),
            ),
            Sidebar(
                Box(
                    Stack(
                        H3("Sidebar", anchor=False),
                        Button("The Sidebar Item 1"),
                        ...
                    ),
                ),
            ),
        ),
        classes=["large"],
    ),
    style={"margin-block": "2rem"},
)
Made with Ludic and HTMX and 🐍 • DiscordGitHub