3: CSS

Phlo has its own compact CSS syntax: no semicolons, no braces required for single rules, and $variables that compile to CSS custom properties. In this chapter you give the poll a dark card layout and a small theme, in a dedicated style file.

3.1: A style file

Style can live in any .phlo file, but a dedicated file keeps things tidy. Create poll.style.phlo:

<style ns=app>
body {
    margin: 0
    background: #0d0f12
    font-family: system-ui, sans-serif
}
main.poll {
    max-width: 560px
    margin: 8vh auto
    padding: 0 24px
}
</style>

The ns=app namespace tells the build which bundle this CSS belongs to; everything in the app namespace is compiled into www/app.css, which view() links automatically. ns=app is also the default, but writing it out keeps larger apps readable.

Reload http://localhost/poll: centered column, dark background. The build ran automatically on the request and regenerated app.css.

3.2: One declaration per line

The CSS parser treats every line as one complete declaration, and the colon does double duty as both selector nesting and property separator:

.card {
    background: #16181d
    border-radius: 12px
    padding: 24px
    margin-bottom: 16px
}
h1: margin: 0 0 24px
.card: p: line-height: 1.6em

h1: margin: 0 0 24px is a complete rule on one line. .card: p: ... nests: it compiles to .card p { line-height: 1.6em; }. Never wrap a value across lines unless you end the property line with a bare : or end each continuation line with a comma; anything else is a build error.

Add the .card block and the h1 line to poll.style.phlo and reload: the buttons now sit in a card.

3.3: Theme variables

$name in a style block becomes the CSS custom property --name, and every place you use it becomes var(--name). Define the theme once in :root and use it everywhere. This is the full poll.style.phlo for the rest of the tutorial:

<style ns=app>
:root {
    $text: #f4f4f5
    $surface: #16181d
    $primary: #ff4a00
    $border: #2a2e36
    $muted: #9aa0aa
}
body {
    margin: 0
    background: #0d0f12
    color: $text
    font-family: system-ui, sans-serif
}
main.poll {
    max-width: 560px
    margin: 8vh auto
    padding: 0 24px
}
h1: margin: 0 0 24px
.card {
    background: $surface
    border: 1px solid $border
    border-radius: 12px
    padding: 24px
    margin-bottom: 16px
}
form: display: inline
button {
    background: $primary
    color: $text
    border: none
    border-radius: 8px
    padding: 10px 18px
    margin-right: 8px
    cursor: pointer
}
</style>

Five variables carry the whole theme: $text, $surface, $primary, $border, and $muted (you use $muted in the next chapter for the vote counts). Want a light theme later? Change five lines in :root.

3.4: Check the output

Look at what the compiler produced:

docker run --rm -v $(pwd)/app:/app ghcr.io/q-ainl/phlo cat /app/www/app.css

You see regular CSS: :root { --text: #f4f4f5; ... }, button { background: var(--primary); ... }. Phlo writes the semicolons, the braces, and the var() wrappers; you write one declaration per line.

Reload http://localhost/poll: a dark card with the question and four orange buttons. The page looks like a poll now. It just cannot count yet.

We use essential cookies to make this site work. With your permission we also use analytics to improve the site.