|
|
@@ -1,172 +1,71 @@
|
|
|
|
# NiceGUI Visual Styling And CSS
|
|
|
|
# NiceGUI Page Structure, Typography, And Scaling
|
|
|
|
|
|
|
|
|
|
|
|
Use this reference for cosmetic and presentational work: themes, color roles, utility classes, CSS properties, responsive layout, and static assets. For the mechanics of how a NiceGUI Python element maps to a Quasar Vue component, including props, events, slots, methods, teleported content, and wrapper-owned state, load [component mechanics](./component-mechanics.md).
|
|
|
|
Use this reference for the physical structure of a NiceGUI page: container geometry, Tailwind layout classes, spacing, overflow, responsive reflow, font loading, typography, and scale. Prefer NiceGUI's Python mechanics or Tailwind classes wherever they can express the requirement; custom CSS is the fallback, not a parallel styling path. For the mechanics of how a NiceGUI Python element maps to a Quasar Vue component, including props, events, slots, methods, teleported content, and wrapper-owned state, load [component mechanics](./component-mechanics.md).
|
|
|
|
|
|
|
|
|
|
|
|
For package boundaries, dependency direction, and page or component ownership, load [application architecture](./architecture.md).
|
|
|
|
For package boundaries, dependency direction, and page or component ownership, load [application architecture](./architecture.md).
|
|
|
|
|
|
|
|
|
|
|
|
## Visual Styling Boundary
|
|
|
|
## Page Structure Boundary
|
|
|
|
|
|
|
|
|
|
|
|
This page owns how an element looks and fits into a page after the correct component and behavior have been chosen. Typical concerns include:
|
|
|
|
This page owns how elements occupy and share space after the correct components and behavior have been chosen. Typical concerns include:
|
|
|
|
|
|
|
|
|
|
|
|
- application color roles and light or dark presentation
|
|
|
|
- page shells, content-width constraints, columns, rows, and grid tracks
|
|
|
|
- width, height, spacing, alignment, wrapping, and overflow
|
|
|
|
- width, height, spacing, alignment, wrapping, overflow, and scroll ownership
|
|
|
|
- typography, borders, shadows, focus treatments, and state colors
|
|
|
|
- font resources, font families, type sizes, weights, line height, and line length
|
|
|
|
- responsive page composition and stable control dimensions
|
|
|
|
- responsive page composition and stable control dimensions
|
|
|
|
- reusable application classes, CSS custom properties, and static assets
|
|
|
|
- rem-based sizing, browser text enlargement, and explicit element scaling
|
|
|
|
|
|
|
|
- exceptional CSS that cannot be expressed through Python mechanics or Tailwind classes
|
|
|
|
|
|
|
|
|
|
|
|
The companion [component mechanics](./component-mechanics.md) reference owns how behavior crosses framework boundaries. Use it when the question is whether a value belongs in a constructor, Quasar prop, Vue event, slot, method, binding, or teleported popup.
|
|
|
|
The companion [component mechanics](./component-mechanics.md) reference owns how behavior crosses framework boundaries. Use it when the question is whether a value belongs in a constructor, Quasar prop, Vue event, slot, method, binding, or teleported popup.
|
|
|
|
|
|
|
|
|
|
|
|
## Visual Styling Workflow
|
|
|
|
## Precedence: Python, Then Tailwind, Then CSS
|
|
|
|
|
|
|
|
|
|
|
|
Escalate only as far as the visual requirement needs:
|
|
|
|
Apply this order to every structural requirement:
|
|
|
|
|
|
|
|
|
|
|
|
1. Use a NiceGUI constructor argument when it directly expresses appearance, such as an icon, color, or size.
|
|
|
|
1. Use NiceGUI's Python composition and component APIs: containers such as `ui.row`, `ui.column`, and `ui.grid`, constructor arguments, documented properties, slots, and wrapper methods.
|
|
|
|
2. Use documented Quasar appearance props through `.props(...)` for component variants such as `outlined`, `rounded`, or `dense`.
|
|
|
|
2. Add Tailwind classes through `.classes(...)` for width, tracks, spacing, alignment, wrapping, overflow, responsive changes, typography, and other physical presentation.
|
|
|
|
3. Use Tailwind classes for page structure and common visual utilities.
|
|
|
|
3. Use Quasar props or helper classes when the requirement belongs specifically to a Quasar component and NiceGUI exposes that boundary.
|
|
|
|
4. Use Quasar utility classes for Quasar spacing, typography, semantic colors, visibility, and positioning.
|
|
|
|
4. Use `.style(...)` only for a calculated runtime value that cannot be represented by the available APIs or utility classes.
|
|
|
|
5. Use `.style(...)` for a calculated runtime value or a short-lived visual probe.
|
|
|
|
5. Add scoped static CSS only when all preceding layers cannot express the requirement without relying on unsupported component internals.
|
|
|
|
6. Move stable or repeated declarations into a scoped static stylesheet under an application-owned class.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Stop when the required presentation is achieved. If a proposed rule needs selectors such as `.q-field__control`, changes a popup's mounting or positioning behavior, or depends on generated Vue markup, resolve the component mechanics first instead of compensating with CSS.
|
|
|
|
Do not create a stylesheet merely to rename or group utilities that fit cleanly in `.classes(...)`. Reuse a Python component or helper when a class sequence repeats. Before adding CSS, identify the unsupported requirement it solves; if the rule needs selectors such as `.q-field__control`, changes popup positioning, or depends on generated Vue markup, resolve the component mechanics first instead of compensating with CSS.
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
```python
|
|
|
|
ui.select(
|
|
|
|
(
|
|
|
|
options=items,
|
|
|
|
ui.select(options=items, label="Item")
|
|
|
|
label="Item",
|
|
|
|
.props("outlined")
|
|
|
|
).props(
|
|
|
|
.classes("w-full md:max-w-md rounded")
|
|
|
|
"outlined popup-content-class=app-item-menu"
|
|
|
|
|
|
|
|
).classes(
|
|
|
|
|
|
|
|
"app-item-select w-full md:max-w-md"
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```css
|
|
|
|
## Physical Layout Model
|
|
|
|
.app-item-select {
|
|
|
|
|
|
|
|
border-radius: 0.25rem;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.app-item-menu {
|
|
|
|
Four layout decisions control most NiceGUI page structure:
|
|
|
|
max-height: min(24rem, 60dvh);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Application Themes With NiceGUI And Quasar
|
|
|
|
| Decision | Typical declarations | Failure when omitted |
|
|
|
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
|
|
|
| outer constraint | `w-full`, `max-w-*`, `mx-auto`, `px-*` | content touches viewport edges or becomes unreadably wide |
|
|
|
|
|
|
|
|
| track sizing | `flex-1`, `shrink-0`, `grid-cols-*`, `minmax(0, 1fr)` | sidebars collapse or content forces tracks wider than the viewport |
|
|
|
|
|
|
|
|
| intrinsic minimums | `min-w-0`, `min-h-0` | flexible children refuse to shrink and create page-level overflow |
|
|
|
|
|
|
|
|
| overflow owner | `overflow-auto`, `overflow-x-auto`, `overflow-hidden` | multiple nested scrollers or clipped interactive content |
|
|
|
|
|
|
|
|
|
|
|
|
Treat a theme as three related layers with different owners:
|
|
|
|
NiceGUI rows and columns provide component structure, while their `.classes(...)` values define the physical constraints. Prefer explicit Tailwind `p-*` and `gap-*` classes for local container spacing. NiceGUI's `--nicegui-default-padding` and `--nicegui-default-gap` variables, both `1rem` by default, are CSS-level exceptions for changing the framework-wide baseline rather than one container.
|
|
|
|
|
|
|
|
|
|
|
|
1. Configure Quasar's named color roles through NiceGUI.
|
|
|
|
|
|
|
|
2. Let Quasar own light, dark, and automatic mode state.
|
|
|
|
|
|
|
|
3. Define application semantic tokens for surfaces and content not covered by Quasar components.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Do not implement a parallel theme switch by replacing Quasar classes or directly restyling each component. NiceGUI's color APIs set the supported Quasar `--q-*` custom properties, so Quasar components, `color=` arguments, and classes such as `text-primary` and `bg-positive` stay aligned.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Set The App-Wide Palette Once
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use [`app.colors()`](https://nicegui.io/documentation/colors#app-wide-colors) in the composition layer for the default palette. Prefer Quasar's semantic roles over shade names: `primary`, `secondary`, `accent`, `positive`, `negative`, `info`, and `warning`. The `dark` and `dark_page` arguments configure dark surface colors; they do not enable dark mode.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
from nicegui import app, ui
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app.colors(
|
|
|
|
|
|
|
|
primary="#176b5b",
|
|
|
|
|
|
|
|
secondary="#52645f",
|
|
|
|
|
|
|
|
accent="#c05a32",
|
|
|
|
|
|
|
|
dark="#202523",
|
|
|
|
|
|
|
|
dark_page="#151917",
|
|
|
|
|
|
|
|
positive="#2e7d32",
|
|
|
|
|
|
|
|
negative="#b3261e",
|
|
|
|
|
|
|
|
info="#276b8e",
|
|
|
|
|
|
|
|
warning="#a86600",
|
|
|
|
|
|
|
|
brand="#176b5b",
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ui.page("/")
|
|
|
|
|
|
|
|
def index() -> None:
|
|
|
|
|
|
|
|
ui.button("Save")
|
|
|
|
|
|
|
|
ui.label("Current workspace").classes("text-brand")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ui.run()
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Custom names such as `brand` become Quasar color names and can be used through `color="brand"`, `text-brand`, or `bg-brand`. Register them before any component uses them. `app.colors()` was added in NiceGUI 3.6.0; for an older pinned version, centralize the same `ui.colors(...)` call in a shared page shell.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use [`ui.colors()`](https://nicegui.io/documentation/colors) only when one page intentionally overrides the app palette. It is page-scoped and takes precedence over `app.colors()`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
@ui.page("/operations")
|
|
|
|
|
|
|
|
def operations_page() -> None:
|
|
|
|
|
|
|
|
ui.colors(primary="#8f3d2c")
|
|
|
|
|
|
|
|
ui.button("Operations action")
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Avoid scattering `ui.colors()` calls among reusable components. A component should consume semantic roles from its owning page rather than silently changing the palette for the whole page.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Let Quasar Control Light And Dark Mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use [`ui.dark_mode()`](https://nicegui.io/documentation/dark_mode) for page mode. Its value is tri-state: `True` enables dark mode, `False` disables it, and `None` follows the client's `prefers-color-scheme` setting. It overrides the `dark` default supplied to `ui.run()` or `@ui.page` for that page.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
dark_mode = ui.dark_mode(None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with ui.button_group():
|
|
|
|
|
|
|
|
ui.button("System", on_click=dark_mode.auto)
|
|
|
|
|
|
|
|
ui.button("Light", on_click=dark_mode.disable)
|
|
|
|
|
|
|
|
ui.button("Dark", on_click=dark_mode.enable)
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Quasar applies `body--light` or `body--dark`, updates its dark-aware components, and tracks system changes while mode is automatic. Use the NiceGUI element instead of invoking Quasar's JavaScript Dark plugin directly. Persist an explicit user preference separately when it must survive navigation or a new browser session.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Add Semantic Tokens For Application Surfaces
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Quasar's brand roles cover framework components, not every application-specific surface. Define a small set of semantic CSS variables in the static stylesheet and change their values under Quasar's documented `.body--dark` class:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```css
|
|
|
|
|
|
|
|
:root {
|
|
|
|
|
|
|
|
--app-page: #f6f8f7;
|
|
|
|
|
|
|
|
--app-surface: #ffffff;
|
|
|
|
|
|
|
|
--app-text: #202623;
|
|
|
|
|
|
|
|
--app-border: #cbd4d0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.body--dark {
|
|
|
|
|
|
|
|
--app-page: var(--q-dark-page);
|
|
|
|
|
|
|
|
--app-surface: var(--q-dark);
|
|
|
|
|
|
|
|
--app-text: #eef3f0;
|
|
|
|
|
|
|
|
--app-border: #46504b;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
|
|
|
background: var(--app-page);
|
|
|
|
|
|
|
|
color: var(--app-text);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.app-panel {
|
|
|
|
|
|
|
|
background: var(--app-surface);
|
|
|
|
|
|
|
|
border: 1px solid var(--app-border);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Name tokens by purpose, such as `--app-surface` or `--app-muted-text`, rather than by a fixed color such as `--app-gray-100`. Reuse `--q-primary` and the other Quasar variables when the meaning matches. Check text, icon, border, focus, hover, disabled, positive, warning, and negative contrast in both modes; a palette is not complete merely because the page background changes.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Structural Styling With Tailwind
|
|
|
|
## Structural Styling With Tailwind
|
|
|
|
|
|
|
|
|
|
|
|
Use standard [Tailwind utility classes](https://tailwindcss.com/docs/utility-first) for page and component structure:
|
|
|
|
NiceGUI's `.classes()` method attaches Tailwind-compatible classes directly to the rendered element. The structural categories used most often are:
|
|
|
|
|
|
|
|
|
|
|
|
- display, flex, and grid behavior
|
|
|
|
| Concern | Representative classes |
|
|
|
|
- width, height, and maximum-width constraints
|
|
|
|
| --- | --- |
|
|
|
|
- spacing, gaps, padding, and alignment
|
|
|
|
| display and tracks | `flex`, `grid`, `grid-cols-1`, `md:grid-cols-2` |
|
|
|
|
- wrapping, overflow, and responsive variants
|
|
|
|
| growth and shrinkage | `flex-1`, `grow`, `shrink-0`, `basis-*` |
|
|
|
|
- typography and common visual utilities when they fully express the design
|
|
|
|
| dimensions | `w-full`, `h-full`, `min-w-0`, `max-w-6xl`, `size-10` |
|
|
|
|
|
|
|
|
| spacing | `gap-4`, `px-4`, `py-6`, `mx-auto`, `space-y-3` |
|
|
|
|
|
|
|
|
| alignment | `items-start`, `items-center`, `justify-between`, `self-stretch` |
|
|
|
|
|
|
|
|
| wrapping and overflow | `flex-wrap`, `whitespace-nowrap`, `overflow-auto`, `truncate` |
|
|
|
|
|
|
|
|
| positioning | `relative`, `absolute`, `sticky`, `inset-*`, `z-*` |
|
|
|
|
|
|
|
|
| responsive changes | `md:flex-row`, `lg:grid-cols-3`, `xl:max-w-7xl` |
|
|
|
|
|
|
|
|
|
|
|
|
Build the outer layout before fine-tuning individual controls:
|
|
|
|
The [Tailwind width](https://tailwindcss.com/docs/width) and [maximum-width](https://tailwindcss.com/docs/max-width) references distinguish fixed spacing-scale widths, fractions, viewport units, and container-scale constraints. A centered shell normally combines its responsibilities explicitly:
|
|
|
|
|
|
|
|
|
|
|
|
1. Define the page shell and width constraints.
|
|
|
|
|
|
|
|
2. Establish responsive rows, columns, gaps, and wrapping.
|
|
|
|
|
|
|
|
3. Add semantic sections and repeated visual patterns.
|
|
|
|
|
|
|
|
4. Configure component appearance and behavior with constructor arguments and Quasar props.
|
|
|
|
|
|
|
|
5. Add stable application classes for any remaining stylesheet rules.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
```python
|
|
|
|
with ui.column().classes("w-full max-w-6xl mx-auto gap-6 px-4"):
|
|
|
|
with ui.column().classes("w-full max-w-6xl mx-auto gap-6 px-4"):
|
|
|
@@ -177,60 +76,113 @@ with ui.column().classes("w-full max-w-6xl mx-auto gap-6 px-4"):
|
|
|
|
item_grid().classes("w-full flex-1 min-w-0")
|
|
|
|
item_grid().classes("w-full flex-1 min-w-0")
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Use stable width, minimum-width, and flex constraints so labels, icons, validation messages, and loaded content do not shift the surrounding layout.
|
|
|
|
`w-full` fills available inline space, `max-w-6xl` caps line and panel length, `mx-auto` centers the shell, and `px-4` retains edge space below the cap. Inside the row, `shrink-0` protects the sidebar and `min-w-0` allows the flexible content track to become narrower than its intrinsic content.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Tailwind's [responsive variants](https://tailwindcss.com/docs/responsive-design) are mobile-first. Unprefixed classes apply at every size; `md:*` and larger prefixes apply from their minimum width upward. In NiceGUI's default Tailwind setup, verify available classes against the framework version bundled by the installed NiceGUI release. Optional [UnoCSS presets](https://nicegui.io/documentation/section_styling_appearance#unocss_engine) are intentionally not fully compatible with Tailwind, and Tailwind CSS layers are one documented difference.
|
|
|
|
|
|
|
|
|
|
|
|
### Combine Tailwind With Quasar Utilities Deliberately
|
|
|
|
### Combine Tailwind With Quasar Utilities Deliberately
|
|
|
|
|
|
|
|
|
|
|
|
NiceGUI's `.classes()` accepts both Tailwind utilities and the CSS helpers bundled with Quasar. Keep Tailwind as the default for application layout and responsive structure, but use Quasar utilities when they express a Quasar-owned or framework-semantic concern more directly:
|
|
|
|
NiceGUI's `.classes()` accepts both Tailwind utilities and CSS helpers bundled with Quasar. Tailwind remains the default for application layout and responsive structure; Quasar helpers are useful when dimensions should follow Quasar's component conventions:
|
|
|
|
|
|
|
|
|
|
|
|
- [`q-m*` and `q-p*` spacing classes](https://quasar.dev/style/spacing) when spacing should follow Quasar's component scale
|
|
|
|
- [`q-m*` and `q-p*` spacing classes](https://quasar.dev/style/spacing) when spacing should follow Quasar's component scale
|
|
|
|
- [typography helpers](https://quasar.dev/style/typography), such as `text-h6`, `text-subtitle2`, and `text-weight-medium`, for text that should follow Quasar's type system
|
|
|
|
- [typography helpers](https://quasar.dev/style/typography), such as `text-h6`, `text-subtitle2`, and `text-weight-medium`, for text that should follow Quasar's type system
|
|
|
|
- [color palette classes](https://quasar.dev/style/color-palette), such as `text-primary`, `bg-positive`, and `text-negative`, so semantic colors track the palette configured by `app.colors()` or `ui.colors()`
|
|
|
|
|
|
|
|
- [visibility helpers](https://quasar.dev/style/visibility), such as `gt-sm` and `lt-md`, when visibility should use Quasar's configured breakpoints
|
|
|
|
- [visibility helpers](https://quasar.dev/style/visibility), such as `gt-sm` and `lt-md`, when visibility should use Quasar's configured breakpoints
|
|
|
|
- [positioning helpers](https://quasar.dev/style/positioning), such as `absolute-top-right`, when positioning content relative to a Quasar component
|
|
|
|
- [positioning helpers](https://quasar.dev/style/positioning), such as `absolute-top-right`, when positioning content relative to a Quasar component
|
|
|
|
|
|
|
|
- [size and overflow helpers](https://quasar.dev/style/other-helper-classes), such as `fit`, `full-width`, and `overflow-auto`, when matching Quasar layout behavior
|
|
|
|
|
|
|
|
|
|
|
|
Mix the two systems by concern, not by writing competing declarations for the same CSS property. For example, `w-full q-pa-md text-primary` uses Tailwind for width and Quasar for component-scale padding and semantic color. Do not combine `p-4` with `q-pa-md`, or Tailwind and Quasar visibility helpers, on the same element; their cascade order can make the result version-dependent and difficult to review.
|
|
|
|
Do not assign the same property through both systems on one element. For example, `w-full q-pa-md` uses Tailwind for width and Quasar for component-scale padding; adding `p-4` would create competing padding declarations. The same rule applies to Tailwind and Quasar visibility helpers or to Tailwind font sizes and Quasar heading classes.
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
```python
|
|
|
|
with ui.card().classes("w-full max-w-2xl q-pa-md"):
|
|
|
|
with ui.card().classes("w-full max-w-2xl q-pa-md"):
|
|
|
|
ui.label("Inventory summary").classes("text-h6 text-primary")
|
|
|
|
ui.label("Inventory summary").classes("text-h6")
|
|
|
|
ui.label("Review required").classes("text-negative text-weight-medium")
|
|
|
|
ui.label("12 locations").classes("text-subtitle2 text-weight-medium")
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Quasar utilities are global classes, so they need no Vue-specific translation before being passed to `.classes()`. Confirm the available helpers and breakpoints against the Quasar version bundled by the installed NiceGUI release.
|
|
|
|
Tailwind and Quasar do not share breakpoint thresholds. Tailwind's defaults begin `sm` at `40rem` and `md` at `48rem`; Quasar defines `sm` from `600px` and `md` from `1024px`. Keep one breakpoint system responsible for a given layout transition, and confirm the bundled framework versions before relying on exact thresholds.
|
|
|
|
|
|
|
|
|
|
|
|
## Fine Tuning With Static Stylesheets
|
|
|
|
## CSS As A Last Resort
|
|
|
|
|
|
|
|
|
|
|
|
Move stable fine tuning into a static stylesheet after the structure and native component configuration are correct. Static stylesheets provide reusable selectors, media queries, pseudo-classes, CSS variables, and a clear cascade that inline declarations cannot provide.
|
|
|
|
Do not move stable geometry into a stylesheet simply because a Tailwind class string is long. Tailwind arbitrary values can express constraints such as `minmax(...)`, `min(...)`, aspect ratios, and dynamic viewport units while keeping the rule visible beside the Python structure that owns it.
|
|
|
|
|
|
|
|
|
|
|
|
Attach an application-owned class with `.classes()` or a Quasar popup prop, then scope stylesheet rules beneath it:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
```python
|
|
|
|
ui.select(...).props("popup-content-class=app-item-menu").classes(
|
|
|
|
with ui.element("main").classes(
|
|
|
|
"app-item-select w-full md:max-w-md"
|
|
|
|
"grid min-h-0 "
|
|
|
|
)
|
|
|
|
"grid-cols-[minmax(14rem,20rem)_minmax(0,1fr)]"
|
|
|
|
|
|
|
|
):
|
|
|
|
|
|
|
|
sidebar()
|
|
|
|
|
|
|
|
workspace().classes("min-w-0")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ui.select(...).props(
|
|
|
|
|
|
|
|
'outlined popup-content-class="max-h-[min(24rem,60dvh)] overflow-y-auto"'
|
|
|
|
|
|
|
|
).classes("w-full md:max-w-md")
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```css
|
|
|
|
Use `.style()` only when a value is calculated at runtime and no class or component property can represent it. Keep the override on the narrowest element and do not promote it to a shared stylesheet unless it becomes a genuine cross-component rule.
|
|
|
|
.app-item-select {
|
|
|
|
|
|
|
|
--app-field-accent: #176b5b;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.app-item-select:focus-within {
|
|
|
|
Static CSS remains appropriate for browser-level facilities such as `@font-face`, selectors or pseudo-elements with no available utility, and integration with markup that cannot receive classes. Attach an application-owned class through `.classes()` or a documented Quasar prop, then scope the exceptional rule beneath that class.
|
|
|
|
filter: drop-shadow(0 0 0.25rem rgb(23 107 91 / 20%));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.app-item-menu {
|
|
|
|
|
|
|
|
max-height: min(24rem, 60dvh);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use `.style()` when a value is calculated at runtime or while testing a local hypothesis. Once a declaration becomes stable or repeated, move it to the stylesheet and keep only the application class in Python.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Avoid overriding Quasar internals such as `.q-field__label`, `.q-field__native`, `.q-field__control`, and `.q-field__input` unless the public props, slots, and application-level selectors cannot express the requirement.
|
|
|
|
Avoid overriding Quasar internals such as `.q-field__label`, `.q-field__native`, `.q-field__control`, and `.q-field__input` unless the public props, slots, and application-level selectors cannot express the requirement.
|
|
|
|
|
|
|
|
|
|
|
|
Quasar coordinates field height, padding, labels, values, icons, and floating-label transforms. Changing only one internal part tends to cause clipping or overlap.
|
|
|
|
Quasar coordinates field height, padding, labels, values, icons, and floating-label transforms. Changing only one internal part tends to cause clipping or overlap.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Fonts And Typography
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Typography affects physical layout because font metrics determine line breaks, control height, baseline alignment, and the intrinsic width of labels. Treat font loading and the type scale as structural dependencies rather than late decoration.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Font Families And Loading
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Tailwind provides `font-sans`, `font-serif`, and `font-mono`, and supports custom family utilities as documented by [Tailwind font family](https://tailwindcss.com/docs/font-family). Quasar's [typography reference](https://quasar.dev/style/typography) documents its embedded Roboto default and its heading, weight, alignment, wrapping, and case helpers.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For an application-owned typeface, `@font-face` is one of the browser-level cases that warrants CSS. Mount the font with other static assets and declare it once in the shared stylesheet. [MDN `@font-face`](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face) recommends WOFF2 for modern web delivery; `font-display: swap` keeps text available while the resource loads.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```css
|
|
|
|
|
|
|
|
@font-face {
|
|
|
|
|
|
|
|
font-family: "App Sans";
|
|
|
|
|
|
|
|
src: url("/static/fonts/app-sans.woff2") format("woff2");
|
|
|
|
|
|
|
|
font-display: swap;
|
|
|
|
|
|
|
|
font-style: normal;
|
|
|
|
|
|
|
|
font-weight: 400 700;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.app-shell {
|
|
|
|
|
|
|
|
font-family: "App Sans", sans-serif;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Include the real weight range supplied by the font file. Requesting an unavailable weight makes the browser synthesize it and can alter text width. Keep a fallback family so failed or delayed font requests do not leave text unavailable.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Type Size And Line Height
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Tailwind's [font-size utilities](https://tailwindcss.com/docs/font-size) pair named rem-based sizes such as `text-sm`, `text-base`, and `text-xl` with default line heights. Combined forms such as `text-sm/6` set size and line height together. Separate `leading-*`, `font-*`, and text-alignment utilities refine those dimensions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
with ui.column().classes("w-full max-w-[65ch] gap-3"):
|
|
|
|
|
|
|
|
ui.label("Inventory summary").classes("text-2xl/8 font-semibold")
|
|
|
|
|
|
|
|
ui.label("Counts by location and storage area").classes("text-base/7")
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Prefer a small named hierarchy over unrelated one-off sizes. Use `rem`-based utilities so browser font preferences and page zoom remain meaningful, and use a character-based maximum width such as `max-w-[65ch]` for long prose. Avoid viewport-width font sizing: text should reflow at narrow widths rather than shrink to preserve one line.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`em` dimensions inherit and can compound through nested elements; `rem` dimensions refer to the root element and avoid that compounding. The [MDN font-size reference](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size) describes both behaviors and recommends relative sizing for accessibility.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Scaling Boundaries
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The word "scale" can refer to different browser mechanics. They are not interchangeable:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Mechanism | Participates in layout | Appropriate use |
|
|
|
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
|
|
|
| responsive classes and reflow | yes | normal page adaptation across available widths |
|
|
|
|
|
|
|
|
| relative font and spacing units | yes | coherent type and spacing changes that respect browser settings |
|
|
|
|
|
|
|
|
| browser zoom | yes, at the document level | user-controlled magnification that the page must tolerate |
|
|
|
|
|
|
|
|
| CSS `zoom` | yes | exceptional magnification of a bounded region |
|
|
|
|
|
|
|
|
| `transform: scale(...)` | no | transient visual emphasis or a deliberately overlaid preview |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Responsive reflow through Python composition and Tailwind classes is the default for page structure. A narrower page should stack tracks, wrap controls, and retain readable text rather than shrink the entire interface.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[CSS `zoom`](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom) changes the size used by layout, so surrounding content is recalculated. [`transform: scale()`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale) changes only painting; neighboring elements retain the unscaled geometry, and enlarged content can overlap or overflow its box. Treat both as exceptional effects after responsive widths, gaps, and breakpoints have been exhausted.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Stable fixed-format regions such as boards, diagrams, and previews need an explicit box before their contents scale. Combine `aspect-ratio`, a bounded inline size, and local overflow rules so transformed content cannot resize surrounding controls. Scaling animations should respect `prefers-reduced-motion`.
|
|
|
|
|
|
|
|
|
|
|
|
## Responsive Layout
|
|
|
|
## Responsive Layout
|
|
|
|
|
|
|
|
|
|
|
|
Support these layouts only:
|
|
|
|
Support these layouts only:
|
|
|
@@ -239,7 +191,7 @@ Support these layouts only:
|
|
|
|
- landscape desktop: $1920 \times 1080$ with side-by-side panels where they improve scanning
|
|
|
|
- landscape desktop: $1920 \times 1080$ with side-by-side panels where they improve scanning
|
|
|
|
- portrait desktop: $1080 \times 1920$ with stacked panels or a narrow fixed sidebar
|
|
|
|
- portrait desktop: $1080 \times 1920$ with stacked panels or a narrow fixed sidebar
|
|
|
|
|
|
|
|
|
|
|
|
Build the mobile layout first, then add one desktop breakpoint when a row or grid needs more space. Prefer flex wrapping and fluid grids before adding another breakpoint. Use Tailwind classes for page layout and Quasar props for component behavior.
|
|
|
|
Build the mobile layout first, then add one desktop breakpoint when a row or grid needs more space. Unprefixed Tailwind classes define the mobile baseline; breakpoint-prefixed classes alter it at larger widths. Prefer flex wrapping and fluid grids before adding another breakpoint. Use Tailwind classes for page layout and Quasar props for component density and behavior.
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
```python
|
|
|
|
with ui.row().classes("w-full flex-wrap gap-4 lg:flex-nowrap items-start"):
|
|
|
|
with ui.row().classes("w-full flex-wrap gap-4 lg:flex-nowrap items-start"):
|
|
|
@@ -249,12 +201,15 @@ with ui.row().classes("w-full flex-wrap gap-4 lg:flex-nowrap items-start"):
|
|
|
|
|
|
|
|
|
|
|
|
Use `min-w-0` for flexible children, `flex-wrap` for toolbars, and `max-w-* mx-auto` to keep portrait layouts readable. Do not add device-specific component trees, container queries, or custom breakpoints unless a supported layout demonstrates a concrete failure.
|
|
|
|
Use `min-w-0` for flexible children, `flex-wrap` for toolbars, and `max-w-* mx-auto` to keep portrait layouts readable. Do not add device-specific component trees, container queries, or custom breakpoints unless a supported layout demonstrates a concrete failure.
|
|
|
|
|
|
|
|
|
|
|
|
## Loading Stylesheets And Static Assets
|
|
|
|
Height needs an explicit ownership chain. `h-full` only resolves when the containing block has a definite height; viewport-bound workspaces usually need a defined outer height and `min-h-0` on nested flex or grid tracks before an inner `overflow-auto` region can scroll. Prefer dynamic viewport units such as `dvh` for browser UI that changes the visible mobile viewport.
|
|
|
|
|
|
|
|
|
|
|
|
- Mount and link static stylesheets once from the composition layer rather than injecting CSS from individual pages.
|
|
|
|
## Loading Exceptional CSS And Static Assets
|
|
|
|
- Keep custom CSS tokenized with variables and scoped to application classes.
|
|
|
|
|
|
|
|
|
|
|
|
- Keep ordinary layout and typography in Python mechanics and Tailwind classes rather than creating a stylesheet.
|
|
|
|
|
|
|
|
- When exceptional CSS is required, mount and link it once from the composition layer rather than injecting it from individual pages.
|
|
|
|
|
|
|
|
- Keep custom dimensions and font families in named variables or application classes.
|
|
|
|
- Avoid broad rules against Quasar internals.
|
|
|
|
- Avoid broad rules against Quasar internals.
|
|
|
|
- Mount referenced assets in the composition layer.
|
|
|
|
- Mount referenced stylesheets, fonts, and other assets in the composition layer.
|
|
|
|
- Verify mount paths, reverse-proxy rewrites, and cache behavior.
|
|
|
|
- Verify mount paths, reverse-proxy rewrites, and cache behavior.
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
```python
|
|
|
@@ -283,23 +238,29 @@ Check each completed page at these three viewports:
|
|
|
|
2. Landscape desktop at $1920 \times 1080$.
|
|
|
|
2. Landscape desktop at $1920 \times 1080$.
|
|
|
|
3. Portrait desktop at $1080 \times 1920$.
|
|
|
|
3. Portrait desktop at $1080 \times 1920$.
|
|
|
|
|
|
|
|
|
|
|
|
Confirm that page sections do not overlap, toolbars wrap on mobile, desktop panels use the available space without becoming excessively wide, and dialogs remain visible and scroll to their final field.
|
|
|
|
Confirm that page sections do not overlap, toolbars wrap on mobile, desktop panels use the available space without becoming excessively wide, and dialogs remain visible and scroll to their final field. Repeat the checks with browser zoom or text enlargement, a delayed font request, long labels, validation messages, and loaded content. Watch for unexpected page-level horizontal scrolling, nested scroll regions, clipped focus outlines, and layout shifts when the webfont replaces its fallback.
|
|
|
|
|
|
|
|
|
|
|
|
## Sources
|
|
|
|
## Sources
|
|
|
|
|
|
|
|
|
|
|
|
!!! info "Primary sources"
|
|
|
|
!!! info "Primary sources"
|
|
|
|
- [NiceGUI element styling and props](https://nicegui.io/documentation/element)
|
|
|
|
- [NiceGUI element styling and props](https://nicegui.io/documentation/element)
|
|
|
|
- [NiceGUI binding properties](https://nicegui.io/documentation/section_binding_properties)
|
|
|
|
- [NiceGUI binding properties](https://nicegui.io/documentation/section_binding_properties)
|
|
|
|
- [NiceGUI color theming](https://nicegui.io/documentation/colors)
|
|
|
|
- [NiceGUI styling and appearance](https://nicegui.io/documentation/section_styling_appearance)
|
|
|
|
- [NiceGUI dark mode](https://nicegui.io/documentation/dark_mode)
|
|
|
|
|
|
|
|
- [Quasar components](https://quasar.dev/vue-components)
|
|
|
|
- [Quasar components](https://quasar.dev/vue-components)
|
|
|
|
- [Quasar spacing classes](https://quasar.dev/style/spacing)
|
|
|
|
- [Quasar spacing classes](https://quasar.dev/style/spacing)
|
|
|
|
- [Quasar typography helpers](https://quasar.dev/style/typography)
|
|
|
|
- [Quasar typography helpers](https://quasar.dev/style/typography)
|
|
|
|
|
|
|
|
- [Quasar breakpoints](https://quasar.dev/style/breakpoints)
|
|
|
|
- [Quasar visibility helpers](https://quasar.dev/style/visibility)
|
|
|
|
- [Quasar visibility helpers](https://quasar.dev/style/visibility)
|
|
|
|
- [Quasar positioning helpers](https://quasar.dev/style/positioning)
|
|
|
|
- [Quasar positioning helpers](https://quasar.dev/style/positioning)
|
|
|
|
- [Quasar color palette and runtime brand variables](https://quasar.dev/style/color-palette)
|
|
|
|
- [Quasar size and overflow helpers](https://quasar.dev/style/other-helper-classes)
|
|
|
|
- [Quasar dark mode](https://quasar.dev/style/dark-mode)
|
|
|
|
|
|
|
|
- [Quasar field](https://quasar.dev/vue-components/field/)
|
|
|
|
- [Quasar field](https://quasar.dev/vue-components/field/)
|
|
|
|
- [Quasar select](https://quasar.dev/vue-components/select/)
|
|
|
|
- [Quasar select](https://quasar.dev/vue-components/select/)
|
|
|
|
|
|
|
|
- [Tailwind width utilities](https://tailwindcss.com/docs/width)
|
|
|
|
|
|
|
|
- [Tailwind maximum-width utilities](https://tailwindcss.com/docs/max-width)
|
|
|
|
|
|
|
|
- [Tailwind font-family utilities](https://tailwindcss.com/docs/font-family)
|
|
|
|
|
|
|
|
- [Tailwind font-size utilities](https://tailwindcss.com/docs/font-size)
|
|
|
|
- [Tailwind responsive design](https://tailwindcss.com/docs/responsive-design)
|
|
|
|
- [Tailwind responsive design](https://tailwindcss.com/docs/responsive-design)
|
|
|
|
|
|
|
|
- [MDN `@font-face`](https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face)
|
|
|
|
|
|
|
|
- [MDN `font-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size)
|
|
|
|
- [MDN `zoom`](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom)
|
|
|
|
- [MDN `zoom`](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom)
|
|
|
|
|
|
|
|
- [MDN `scale()`](https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale)
|