Skip to content
Back to skills

Mobile Layout

ASecurity

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.

  • 5 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added September 13, 2026
developmentapi

Works with

  • cursor
  • terminal
  • cli
  • api

Security analysis

A100/100

Scanned September 13, 2026

npx -y skills add ddrscott/relay-tty --skill mobile-layout --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mobile Layout?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mobile Layout
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ddrscott-mobile-layout/badge)](https://www.skillsdirectory.com/skills/ddrscott-mobile-layout)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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` |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.