Raft 设计系统

模式

Responsive layout

The breakpoints, what each width shows, how short desktop windows shrink, how a row gives way when it runs out of room, what replaces hover on a touch screen, and how phone layouts hold at 320px.

本页尚未翻译
译文完成之前,这里显示英文原文。 阅读英文版

Below 768px Raft is a phone layout: top-level pages with the tab bar, everything else pushed. From 768px the desktop layout begins, with the web top bar and the rail, and side panels sit beside the main area once there is room for both. Where there isn't room, a panel covers the main area rather than squeezing it below the widths in the table. Task details don't change with the width beyond going full screen on a phone (Tasks).

When it applies

Every screen. The regions themselves are in Page structure; the widths of regions are in Spacing. A product can add its own conditions, such as the widths of Raft Chat's Search and Activity columns (Raft Chat).

Structure

WidthLayout
Below 768pxPhone: top-level pages with the tab bar, every other page pushed. No web top bar and no rail. A thread is a pushed page; a profile covers the page like one, with Back
768px to 1023pxWeb top bar, rail, sidebar and main area. A profile covers the main area
1024px and upA profile or a task side panel (400px, resizable from 320px to 640px) sits beside the main area when the area it opens in is at least 720px wide, the main area's 360px plus the panel's 360px; otherwise it covers it
A thread, at any desktop widthBeside the conversation when the window is landscape or at least 1280px wide, and the conversation's column is at least 720px wide (the conversation's 360px plus the thread's 360px minimum); otherwise it covers the conversation. Beside it, the thread is 400px (resizable from 360px to 720px) and the conversation keeps at least 360px
Desktop window shorter than 600pxHeaders shrink from 56px to 48px; the rail shrinks with them, from 57px to 49px wide; rail items shrink from 40px to 36px. The web top bar keeps 48px

The mobile apps switch by the window's width too, at their own breakpoint: from 840dp, with the app's desktop mode on, they show the rail and two panes instead of the tab bar, in landscape and on tablets alike, and a thread sits beside the conversation from 1200dp. The rail is drawn as the AppRail and keeps the phone's destinations in the phone's order. Keep each platform's breakpoint (768px on the web, 840dp in the apps) rather than forcing one: a breakpoint is how a layout is built, while the navigation's structure, which is the same everywhere, is in Navigation.

app-shell/compositions/responsive

Rules

When a row runs out of room

A toolbar, a header or a filter row has to fit at the narrowest width its region can take (the Activity results list goes down to 320px), in the longest translation. When it doesn't, its parts give way in a fixed order, so the person still sees every control:

  1. A secondary text button shows only its icon, with its label kept as the accessible name and the tooltip. Mark all read becomes the check-check icon button.
  2. Only then, the main control shows only its icons: a segmented control's segments, a tab's label. A segmented control does this itself below the row width set in iconsOnlyBelow: each segment becomes a 32px square with its icon, its label kept as the accessible name and the tooltip (SegmentedControl).
  3. Text truncates last, and only in a name (a channel, a person), never in a control's label.
  • Never let parts overlap, and never let a control shrink below its own content: wrapping a control in min-w-0 lets its frame shrink while its content spills onto its neighbor.
  • Decide the switch with a container query on the row (@container, @max-[…]:), not the window width: the same row sits in columns of different widths.
  • Don't shrink text or a control's height to make a row fit: a label too small to read, or a target too small to hit, is worse than an icon with a tooltip.

Touch screens

A touch screen has no hover, so anything that only appears on hover is out of reach there. Decide by the input, not the width: use the pointer: coarse media query, because a tablet held sideways is touch and a narrow desktop window still has a mouse.

  • With a mouse, keep a row's actions hover-only, Mark as Done on an Activity row included: show them while the row is hovered, holds keyboard focus or has a menu open from it, and hide them at rest. A list where every row shows its button reads as a wall of buttons and pulls the eye from the content, and the row itself is what a mouse goes for. Hidden actions stay in the tab order.
  • Show a row's hover action at rest on a touch screen when it is the row's main action, such as Mark as Done on an Activity row: a 44px target at the end of the row, with its icon. The rest of the row makes room for it instead of sitting under it (InboxItem).
  • Put every hover action in the row's press-and-hold menu as well, the same menu right-click opens on desktop, so an action is in one place on every device (Conversation).
  • A swipe may add a shortcut for the row's main action (swipe left to reveal Mark as Done, release to apply, with an Undo toast), but never be the only way to reach it (Accessibility).
  • Keep secondary hover actions out of the row on a touch screen; they live in the menu, so a list stays calm.

Phone

  • Design for 390px wide, and make everything fit at 320px, the narrowest phone still in use.
  • Truncate long names. What a long value does in a form field, and what wraps instead, is in Forms.
  • Let buttons wrap to a new line. Don't shrink their text: a label too small to read is worse than a taller button.
  • Use at most 4 segments in a segmented control. When they don't fit, show only their icons, with the label kept as the accessible name (iconsOnlyBelow).
  • Scroll tabs horizontally when they don't fit (Tabs).
  • The composer and the message actions on a touch screen are in Conversation.