首页 / Skills / 网页与界面设计 / 破坏界面 Break UI
网页与界面设计

破坏界面 Break UI

Emil KowalskiMITSkill 语言: 英文
协议已核对不含脚本低风险
演示真实运行记录 · claude-sonnet-5-5 · 2026年10月
Stress-test this component for me. I can't give you a browser or a dev server, so reason from the code and say which findings are inferred. Do not write any files; give me the report only. The schema allows name up to 255 chars, email up to 254, title up to 120, and there is no limit on member count. ```jsx function MemberRow({ member }) { const initials = member.name.split(' ')[0][0] + member.name.split(' ')[1][0]; return ( <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}> <img src={member.avatar} className="avatar" style={{ width: 40, height: 40, borderRadius: '50%' }} /> <div> <div className="name">{member.name}</div> <div className="email">{member.email}</div> <div className="role">{member.title || '-'}</div> </div> <span className="badge">{member.status}</span> <button className="menu">...</button> </div> ); } function Header({ count }) { return <h2>{count} members</h2>; } ``` Demo data: { name: 'Jane Doe', email: '[email protected]', title: 'Designer', status: 'active', avatar: '/a/jane.png' }, count 12.
Skill: break-ui

Stress test: MemberRow and Header

I built no toggle and wrote no files, as you asked. I didn't render anything either, so every finding below is inferred from the JSX. I couldn't see your CSS for .avatar, .name, .email, .role, .badge or .menu, nor the parent list. Any finding that depends on those is marked.

Surface map

Field Source Limit Optional?
name member.name 255 No
email member.email 254 No
title member.title 120 Yes (|| '-')
status member.status Enum values unknown No
avatar member.avatar Unknown Probably, since there's no fallback
count Header prop Unbounded No
Member list Parent (not shown) Unbounded Can be empty

Part 1: What broke

# Severity Field Worst-case value What happens Fix
1 Broken name 'Jo', 'Madonna', '张伟', '' name.split(' ')[1] is undefined, so undefined[0] throws a TypeError. The row crashes during render. Without an error boundary, the whole member list unmounts. One-word names and Chinese or Japanese names (which have no spaces) are common. The initials variable is never used, so the crash buys nothing. Delete the line, or replace it with a safe helper that takes the first and last word, uses Intl.Segmenter for graphemes and falls back to an icon. Then use it as the avatar fallback (see #4).
2 Broken email 254-char email, or a realistic [email protected] An email has no break opportunities. The text column is a flex child with min-width: auto, so it can't shrink below the string's width. It pushes the badge and ... menu off the row or clips them, and the menu becomes unreachable. min-width: 0 on the text column. overflow-wrap: anywhere on .email (or ellipsis plus a title). flex-shrink: 0 on the badge and the button.
3 Ugly avatar Any long name or email The <img> has width: 40 but the default flex-shrink: 1, so it can squash into a narrow oval when the text column is wide. flex-shrink: 0 on the avatar. Add object-fit: cover for non-square photos.
4 Ugly avatar undefined, '', or a 404 URL There's a broken-image icon, or an empty src that may re-request the page. There's no onError and no initials fallback. Fall back to an initials circle on missing src or onError.
5 Ugly name 255 chars with spaces (such as a full legal name with several surnames) It wraps to many lines. With align-items: center, the avatar, badge and menu float mid-height. With no margin-left: auto, the badge and menu sit right after the text, so they don't line up between rows. That last part may already show with demo data, depending on your CSS. align-items: flex-start. Clamp .name to 2 lines (with a title). margin-left: auto on the badge.
6 Ugly title Missing, '', or ' ' A bare - shows under the email. Whitespace-only passes the || check and renders an empty line. Trim the title. Omit the line when empty.
7 Ugly status Raw enum value such as pending_invite, or a localized label The badge shows the raw value, so underscores and lowercase appear. A long label can wrap because the badge may shrink. An unknown value or null gives a blank or meaningless pill. Map status to a label and a style, with a fallback. white-space: nowrap; flex-shrink: 0.
8 Ugly count 1, 0, 1284, null "1 members", "0 members", unseparated 1284, and " members" when null. Intl.PluralRules (or separate strings). Intl.NumberFormat. Guard null.
9 Fragile member list 1,000+ members The schema has no limit, and nothing here paginates or virtualizes. If the parent maps every member, that is thousands of rows with inline style objects, with no React.memo. The Header count can also disagree with the number of rows rendered if the list is paginated. Virtualize or paginate (decide in Part 2). Make sure count comes from the total, not list.length.
10 Fragile ... button Any It has no accessible name (screen readers read "dot dot dot"). It has no type="button", so it submits if the row is ever inside a <form>. aria-label="Member actions" and type="button".
11 Fragile <img> Any There's no alt, so the screen reader may read the filename. alt="" if decorative, or alt={member.name}.
12 Fragile RTL, 200% zoom, dark mode n/a These depend on your CSS. The inline gap and flexbox are direction-safe. Zoom will make #2 and #5 worse. Dark mode can't be judged from the JSX. Check these once the fixes are in.

Part 2: Decisions for you

  • Name: I recommend wrapping at 2 lines, with the full value in title. People identify each other by name, so I wouldn't truncate it.
  • Email: I recommend wrapping with overflow-wrap: anywhere. If you truncate instead, use the middle, because long emails often differ only in the local part or the domain.
  • Title: I recommend one line with an end ellipsis and a title, since it's secondary info.
  • Missing title: I recommend omitting the line. This is a minor call, but a lone - looks like a bug.
  • Long member list: I recommend pagination if the list is mostly searched or filtered. If people scroll it as a roster, virtualize it instead.

Part 3: What held up

  • Escaping: React escapes all the text, so a name like <b>x</b> or &amp; shows literally. There's no dangerouslySetInnerHTML.
  • Missing title: A missing or empty title doesn't crash, apart from the cosmetic dash in #6.
  • Row layout: The row has no fixed width or height, so it can grow with its content.
  • Avatar shape: borderRadius: '50%' on a fixed 40×40 gives a circle at rest.
  • Demo data: With Jane Doe, the single-line layout looks fine, and "12 members" is correct.

Not covered

I haven't seen the parent list, its keys, its empty state (zero members) or its loading state. Those are worth a look next. I also didn't test emoji-first names or diacritic clipping, since both depend on CSS I can't see. Once #1 is fixed, an emoji-first name will come out wrong in any initials code that doesn't use graphemes.

The most urgent fix is #1, because it can take down the whole page. Say fix all or fix 1, 2, 3 and I'll apply them, though you asked for no file edits for now.

Test run: a small member-row component pasted as code. No browser or dev server was available, so the model said every finding is inferred and wrote no files, as asked. It did not open the Skill's CATALOG.md in this run. It found a crash for one-word names and several layout breaks.

它做什么

拿一个用演示数据看起来很好的界面,把“挑过的好数据”还原成真实情况。它先列出组件渲染的每个值及其上限(来自校验规则、数据库或接口),再从一份“容易搞坏界面的值”目录里拼出最坏数据:很长和带变音符号的姓名、无法折行的邮箱和网址、单字名和以表情开头的名字、数量恰好为 1、空列表和超长列表、缺失的图片和字段。这些数据从与演示数据相同的入口进入,放在一个仅限开发环境的“演示数据 / 最坏数据”开关后面。它会在组件的真实宽度、320px、200% 缩放、深色模式和 RTL 下检查,然后逐条报告问题,包含表现、原因、严重程度(崩溃、难看、脆弱)和修法。它在动手修之前停下,由你来决定。

输出

问题表、需要你拍板的决定(截断还是换行、空状态怎么显示)、已经扛住的情况,以及怎么应用修复。

适合什么场景

想在真实用户之前发现版面和数据问题的开发者与设计师。

说明与风险

低风险:纯指令文件,没有脚本,不联网。在项目里它可能添加一个仅限开发环境的开关和一个最坏数据文件;它会先报告,你要求才修改,但请检查它写入的任何文件。已用一个粘贴的组件、没有浏览器的条件试用一次:它说明所有结论都是推断,没有写文件,找出了单词名字会导致崩溃,以及几处版面问题。这次它没有打开自带的目录文件。没有带问题调用时,它只回复一句问候。作者 Emil Kowalski,MIT 协议。

SKILL.md 原文包内共 3 个文件