This skill should be used when modifying CSS layout, adding full-screen overlays, changing overflow properties, working with mobile keyboard viewport, adding `position: fixed` elements, or changing height units (vh, dvh, h-screen, h-app) in relay-tty. Prevents recurring layout bugs on mobile.
Scanned 9/13/2026
Install to Claude Code
npx -y skills add ddrscott/relay-tty --skill mobile-layout --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Mobile Layout?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ddrscott-mobile-layout)More formats (shields.io, HTML) on the badges page.
---
name: Mobile Layout & Viewport Rules
description: This skill should be used when modifying CSS layout, adding full-screen overlays, changing overflow properties, working with mobile keyboard viewport, adding `position: fixed` elements, or changing height units (vh, dvh, h-screen, h-app) in relay-tty. Prevents recurring layout bugs on mobile.
---
# Mobile Layout & Viewport Rules
This project has a specific CSS architecture for mobile that has been debugged through multiple iterations. Violating these rules causes hard-to-diagnose bugs on Android and iOS. Apply these rules whenever touching layout, overflow, or positioning CSS.
## The Height Chain
```
html -- NO overflow:hidden, only overscroll-behavior:none
body.h-app -- overflow:hidden, height tracks --app-h
.drawer.h-app -- DaisyUI drawer, also tracks --app-h
main.h-app -- session view
header -- fixed height toolbar
.flex-1 -- terminal area (takes remaining space)
toolbar -- mobile key row (fixed height)
```
`--app-h` is set by `useKeyboardViewport` hook to `visualViewport.height` on mobile. This is the only height variable that correctly tracks the keyboard on both iOS and Android.
## Rules
### 1. Never set `overflow: hidden` on `<html>`
`overflow: hidden` on `<html>` clips `position: fixed` elements on mobile browsers. This breaks all full-screen overlays (history picker, file browser, modals).
**Only** `overscroll-behavior: none` is safe on html.
### 2. Full-screen overlays must use `position: fixed`
```jsx
<div className="fixed inset-0 z-[9999] ...">
```
- Use `fixed inset-0`, never `absolute inset-0` for true full-screen overlays
- Use `z-[9999]` or similarly high value to beat all stacking contexts
- `position: fixed` escapes parent `overflow: hidden` — this is correct CSS behavior
- Never rely on `z-50` alone — DaisyUI drawer and toolbar backdrop-blur create stacking contexts
### 3. Use `h-app` instead of `h-screen` for layout containers
- `h-screen` = `100vh` — does NOT shrink when the mobile keyboard opens
- `h-app` = `var(--app-h)` — tracks `visualViewport.height` via the keyboard viewport hook
- Body, drawer, and main must all use `h-app` for the keyboard-aware height chain to work
- Exception: desktop-only views (grid, lanes) can use `h-screen`
### 4. Focus calls on xterm's textarea must use `preventScroll`
```js
textarea.focus({ preventScroll: true });
```
Without `preventScroll`, the browser auto-scrolls to show xterm's hidden textarea (positioned at the cursor), displacing the entire terminal view.
### 5. Never call `scrollIntoView` on xterm's textarea
The `useKeyboardViewport` hook's `scrollIntoView` must skip elements inside `.xterm`:
```js
if (!focused.closest('.xterm')) {
focused.scrollIntoView({ block: "nearest", behavior: "instant" });
}
```
`scrollIntoView` on xterm's textarea scrolls `overflow: hidden` parent containers, pushing the terminal out of view.
### 6. Height-only ResizeObserver changes need long debounce
iOS keyboard suggestion bar toggles rapidly, causing height oscillation. Use 500ms+ debounce for height-only container changes (width changes can be immediate).
### 7. Elements overlaying xterm should be `position: absolute`, not in flex flow
The scratchpad, search bar, and similar inputs that appear above the terminal must use `absolute` positioning relative to the toolbar, not participate in the flex layout. Being in flex flow causes xterm to resize on every open/close.
## Quick Reference
| Element | Height | Overflow | Position |
|---------|--------|----------|----------|
| `html` | (default) | `overscroll-behavior: none` only | static |
| `body` | `h-app` | `overflow-hidden` | static |
| drawer | `h-app` | (DaisyUI default) | relative |
| main | `h-app` | (default) | relative |
| terminal area | `flex-1 min-h-0` | `overflow-hidden` | relative |
| full-screen overlay | `h-app` | (default) | `fixed inset-0 z-[9999]` |
| scratchpad | (auto) | (default) | `absolute bottom-full` |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!