1. Ngữ cảnh: App của bạn — vị khách trong ngôi nhà ChatGPT
Trước khi vẽ nút và chọn phông, cần chấp nhận thực tế: người dùng không mở “trang web của bạn”, họ đang ở trong ChatGPT. ChatGPT đã có sẵn:
- bảng màu,
- phông chữ và kích thước,
- khoảng cách và bố cục phần tử.
Widget của bạn hiển thị trong môi trường đó, thường là bên trong iframe. Từ đây có kết luận quan trọng: về mặt thị giác, App phải trông như phần mở rộng tự nhiên của giao diện ChatGPT, chứ không phải như banner từ năm 2008.
Hướng dẫn chính thức của OpenAI nói đúng điều này: không phá vỡ màu và phông hệ thống, chỉ thêm điểm nhấn thương hiệu vừa phải, và tuân theo kiểu chữ cơ bản cùng lưới của nền tảng.
Về mặt thực hành, điều này có ba điểm.
Thứ nhất, nền, màu văn bản cơ bản, kiểu chữ tiêu chuẩn — tất cả nên được thừa hưởng từ ChatGPT hoặc từ biến hệ thống, chứ không phải “tôi là nghệ sĩ và tôi thấy thế”.
Thứ hai, nếu bạn muốn “phong cách riêng”, nó nên tập trung ở các điểm nhấn: nút chính, badge, trạng thái nổi bật. Nhưng đừng là nền cầu vồng hay phông Comic Sans tuỳ biến — dù trong lòng bạn rất muốn.
Thứ ba, chế độ inline và fullscreen của cùng một App phải trông như một thế giới thống nhất: màu CTA đồng nhất, bo góc và khoảng cách thẻ giống nhau, kiểu chữ giống nhau. Người dùng không nên cảm thấy rằng khi chuyển từ inline sang fullscreen là sang một sản phẩm khác.
Tiếp theo ta đi theo lớp: màu và chủ đề, kiểu chữ, khoảng cách và lưới, rồi — cách Tailwind và shadcn/ui giúp ráp tất cả lại.
Insight
Sandbox của ChatGPT không chỉ giới hạn chức năng widget của bạn mà còn thêm phong cách (styles) của riêng nó.
Thứ nhất — đó là thẻ HTML
Bản gốc trên trang:
<html lang="ru">
Trong sandbox:
<html lang="en-US" data-theme="light" class="light" style="--safe-area-inset-top: 0px; --safe-area-inset-bottom: 0px; --safe-area-inset-left: 0px; --safe-area-inset-right: 0px;">
Thứ hai — đó là các CSS gốc, để widget của bạn giống ChatGPT hơn:
<style>
html,body,#root{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;padding:0}
html,body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Helvetica Neue,Arial,sans-serif!important}
button,input,textarea,select{font-family:inherit}
html{background-color:#fff}
html.dark{background-color:#212121}
html.mobileSkybridge.dark{background-color:#000}
@supports (font: -apple-system-body){html.mobileSkybridge{font:-apple-system-body}}
</style>
Tốt nhất hãy nhớ điều này — sẽ ít bất ngờ hơn.
2. Chủ đề và màu sắc: sống trong hai vũ trụ sáng và tối
Chủ đề sáng và tối
Giao diện ChatGPT đã hỗ trợ chủ đề sáng và tối. Widget của bạn hiển thị trong một trong hai chủ đề đó, và người dùng có thể chuyển đổi bất kỳ lúc nào. Điều đó có nghĩa là mọi nền trắng hoặc đen “cứng” đều là mối nguy tiềm tàng.
Hãy tưởng tượng widget vẽ nền trắng và chữ đen. Ở chủ đề sáng thì tạm ổn. Ở chủ đề tối — như đèn pha chiếu thẳng vào mắt. Tình huống ngược lại với nền đen trong chủ đề sáng cũng chẳng khá hơn. Vì thế khuyến nghị chính thức đề xuất không hard-code màu, mà dựa vào chủ đề/biến của host.
Trong Apps SDK, môi trường thường cung cấp API hoặc biến CSS cho chủ đề hiện tại. Tài liệu có các biến thể như window.openai.theme và sử dụng biến CSS chuẩn của ChatGPT. Ngoài ra vẫn có prefers-color-scheme và tiện ích dark: trong Tailwind.
Ý tưởng đại khái: widget của bạn phải tự động điều chỉnh theo chủ đề của host cho các thứ như:
- nền của thẻ (sáng/tối hơn một chút so với nền cơ bản),
- màu chữ (độ tương phản đủ),
- đường viền, đổ bóng và trạng thái hover.
Ví dụ một wrapper đơn giản cho chủ đề với Tailwind:
// components/AppShell.tsx
export function AppShell({ children }: { children: React.ReactNode }) {
return (
<div className="bg-background text-foreground">
{/* bg-background/text-foreground được theme ghi đè */}
{children}
</div>
);
}
Ở đây bg-background và text-foreground — không phải lớp chuẩn của Tailwind, mà là alias trỏ tới biến CSS của hệ thống thiết kế (ví dụ từ shadcn/ui), vốn liên kết với chủ đề sáng/tối của ChatGPT.
Màu hệ thống vs. điểm nhấn thương hiệu
OpenAI nói khá rõ: không được thay màu hệ thống của ChatGPT. Văn bản cơ bản, các panel chat chuẩn, nền — tất cả phải giữ màu chung của nền tảng. “Sân chơi” của bạn là các điểm nhấn trong widget: nút CTA (call to action — hành động chính), badge, phần tử nhỏ.
Trong thực tế GiftGenius, điều đó có nghĩa là:
- nền thẻ quà tặng gần với nền hệ thống,
- chữ — màu chuẩn như trong chat,
- màu thương hiệu GiftGenius dùng cho nút chính “Chọn quà” và có thể cho badge giảm giá.
Có thể hình dung bằng bảng:
| Thành phần | Nên làm | Tránh |
|---|---|---|
| Nền widget | Kế thừa từ ChatGPT | Đặt gradient thương hiệu rực rỡ |
| Văn bản chính | Kế thừa màu hệ thống | Làm quá màu/màu xám đến mức khó đọc |
| Nút CTA chính | Dùng màu nhấn thương hiệu | Tô “cầu vồng” với 5 màu |
| Nút/liên kết thứ cấp | Gần với liên kết hệ thống | Làm chúng rực rỡ như CTA |
| Bóng/viền | Nhẹ nhàng, tối giản | Viền neon dày |
Ví dụ nhỏ với Tailwind cho màu chính:
// styles/globals.css (đoạn trích)
:root {
--gift-accent: 222 84% 56%; /* hsl */
}
.dark {
--gift-accent: 222 84% 64%; /* sáng hơn một chút cho dark */
}
// components/GiftButton.tsx
export function GiftButton({ children }: { children: React.ReactNode }) {
return (
<button className="rounded-md bg-[hsl(var(--gift-accent))] px-4 py-2 text-sm font-medium text-white hover:opacity-90">
{children}
</button>
);
}
Bạn không đụng vào nền toàn bộ widget, mà áp dụng khéo màu riêng cho nút CTA chính.
Độ tương phản và WCAG một cách thực dụng
Ngay cả khi bạn không “thi” WCAG, có một nguyên tắc đơn giản: văn bản phải dễ đọc. Cỡ chữ càng nhỏ thì tương phản càng cao. Trong các khoá về accessibility, người ta khuyên giữ tương phản giữa chữ và nền không thấp hơn khoảng 4.5:1 cho văn bản chính. Ở đây ta không đi sâu chuẩn chi tiết: ta cần một chỉ dấu thực tế — tương phản chữ và nền đủ dùng.
Trong thực tế:
- đừng dùng chữ xám nhạt trên nền xám nhạt chỉ vì “thanh lịch”;
- tránh chữ xám đậm trên nền gần như đen ở chủ đề tối;
- kiểm tra bằng mắt: nếu bạn phải nheo mắt — người dùng cũng sẽ đau mắt.
Có thể tự đặt quy tắc: mọi văn bản thứ cấp (nhãn, gợi ý) vẫn phải đọc được, chỉ kém nổi bật hơn một chút về màu và kích cỡ, chứ không “mờ như bóng ma”.
3. Kiểu chữ: phông hệ thống, phân cấp và chút lẽ thường
Phông hệ thống thay vì webfont riêng
Hướng dẫn chính thức kêu gọi dùng phông hệ thống của nền tảng như SF Pro, Roboto và tương đương, không tự nhúng webfont riêng. Lý do không chỉ ở hiệu năng, mà còn vì App của bạn nên trông như một phần gốc của giao diện.
Trong ứng dụng Next.js, cách đơn giản nhất là để mọi thứ trong widget thừa hưởng stack phông hệ thống. Trong Tailwind thường đã cấu hình là font-sans. Nếu bạn muốn tường minh hơn:
// app/layout.tsx (đoạn trích)
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="font-sans antialiased">
{children}
</body>
</html>
);
}
Không cần tải 3 họ phông qua Google Fonts. Với GiftGenius cho mục đích học tập, phông hệ thống chỉn chu sẽ gọn gàng hơn nhiều so với kiểu như Lobster.
Phân cấp kích thước
Ta chỉ cần vài cấp độ kiểu chữ: tiêu đề khối, tiêu đề phụ/tham số chính, văn bản chính và chú thích.
Với thẻ inline của GiftGenius, chẳng hạn, có thể thống nhất các mức sau:
| Vai trò | Lớp Tailwind | Ví dụ |
|---|---|---|
| Tiêu đề thẻ | |
Tên quà tặng |
| Thông số chính | |
Giá hoặc danh mục |
| Mô tả | |
Mô tả ngắn |
| Chú thích/chi tiết nhỏ | |
Giao hàng, cửa hàng |
Mini-component thẻ:
// components/GiftCard.tsx
type GiftCardProps = {
title: string;
price: string;
description: string;
};
export function GiftCard({ title, price, description }: GiftCardProps) {
return (
<div className="rounded-lg border bg-card p-4">
<h3 className="text-base font-semibold">{title}</h3>
<p className="mt-1 text-sm font-medium text-emerald-600">{price}</p>
<p className="mt-2 text-sm text-muted-foreground">{description}</p>
</div>
);
}
Ở đây:
- không có H1 khổng lồ;
- thông tin gọn gàng;
- phân cấp dễ nhận biết qua cỡ chữ và độ đậm.
Căn chỉnh và độ dài dòng
Giao diện chat thường hẹp, nhất là ở inline. Vì vậy không cần quá cầu kỳ: căn trái thông thường và độ dài dòng 40–60 ký tự là thoải mái.
Thói quen hữu ích:
- đừng căn giữa các đoạn dài trong thẻ — khó đọc hơn;
- đừng viết TẤT CẢ BẰNG CHỮ HOA;
- đừng để văn bản cơ bản nhỏ hơn 14 px (trong Tailwind là text-sm) trừ khi thực sự cần.
Khi phân vân, hãy nhớ: người đọc là một người mệt mỏi đang dùng điện thoại trên tàu điện, chứ không phải bạn với màn hình 27 inch lý tưởng.
4. Khoảng cách, mật độ và lưới
Nếu màu và phông là “sơn”, thì khoảng cách là không khí. Không có nó, ngay cả thẻ gọn gàng nhất cũng biến thành mớ hỗn độn.
OpenAI nhấn mạnh: các phần tử không nên “dính” vào nhau, nên lấy khoảng cách và bo góc từ hệ thống thiết kế hoặc UI framework (Tailwind, shadcn/ui v.v.), và cần hạn chế cuộn ngang.
Nguyên tắc “biết thở”
Mẫu đơn giản nhất: dùng một thang khoảng cách thống nhất (ví dụ bước 4 px hoặc 8 px) và đừng tự nghĩ ra kích cỡ mỗi lần. Trong Tailwind đã có sẵn: p-2, p-3, p-4, gap-3 v.v.
Ví dụ lưới nhỏ cho danh sách quà ở inline:
// components/GiftListInline.tsx
export function GiftListInline({ children }: { children: React.ReactNode }) {
return (
<div className="flex flex-col gap-3">
{children}
</div>
);
}
Mỗi thẻ cách nhau gap-3, có p-4 bên trong, và chừng đó là đủ để danh sách không trông như “tấm ga”.
Cột: inline so với fullscreen
Trong tài liệu UX cho Apps SDK, khuyến nghị với widget inline là giữ 1–2 cột thẻ, còn fullscreen có thể 2–3 nếu đủ rộng.
Lý do đơn giản: trong chat, chiều rộng hạn chế, nhất là trên di động, và hai cột đã là sát ngưỡng về khả năng đọc. Còn fullscreen thì bạn có gần như toàn màn hình và có thể xếp nội dung dày hơn.
Sơ đồ ước lượng:
flowchart LR
subgraph Inline
A[1 cột
màn hình hẹp]
B[2 cột
trên desktop]
end
subgraph Fullscreen
C[2 cột
kịch bản chính]
D[3 cột
cho lưới/danh mục]
end
Hiện thực trong Tailwind cho GiftGenius:
// components/GiftGrid.tsx
export function GiftGrid({ fullscreen, children }: { fullscreen?: boolean; children: React.ReactNode }) {
const base = fullscreen ? "grid-cols-2 md:grid-cols-3" : "grid-cols-1 sm:grid-cols-2";
return (
<div className={`grid gap-4 ${base}`}>
{children}
</div>
);
}
Ở chế độ inline bạn cho một cột trên di động và hai cột trên màn hình rộng hơn. Ở fullscreen thì dùng ngay 2–3 cột tuỳ chiều rộng.
Tránh cuộn ngang
Chat vốn dĩ là theo trục dọc. Người dùng quen cuộn xuống chứ không cuộn ngang. Vì vậy:
- cố gắng để bảng và thẻ vừa trong bề rộng container;
- đừng đặt width cố định kiểu width: 600px; cho phần tử sống trong container linh hoạt;
- dùng max-w-full, overflow-x-auto chỉ như “phương án cuối”, không phải mặc định.
Với thẻ GiftGenius, thuận tiện là đặt w-full và để lưới quyết định bao nhiêu thẻ trên một hàng.
5. Tính đáp ứng trong container của ChatGPT
Trong frontend thông thường, bạn kiểm soát đầy đủ viewport. Trong ChatGPT, kiểm soát đó bị giới hạn: widget của bạn nằm trong container của chat, có kích thước và quy tắc riêng. Apps SDK cung cấp vài cầu nối hữu ích: chiều cao tối đa, safe area cho phần khuyết màn hình, loại thiết bị, v.v.
maxHeight và giới hạn theo chiều dọc
Ở chế độ inline, ChatGPT có thể giới hạn chiều cao widget để nó không “chiếm” cả màn hình. Hook như useMaxHeight() cho bạn biết hiện có thể chiếm bao nhiêu không gian, và đặt cuộn dọc bên trong khi cần.
Pseudo-code:
// Pseudo-code, không phải API thật:
const maxHeight = useMaxHeight();
return (
<div style={{ maxHeight, overflowY: "auto" }}>
<GiftGrid>{/* ... */}</GiftGrid>
</div>
);
Như vậy bạn tránh được tình huống widget chạm đáy màn hình, còn tin nhắn chat thì “trôi” về quá khứ.
safeArea và thiết bị di động
Trên thiết bị di động có thể có phần khuyết, thanh trạng thái, panel hệ thống. Apps SDK cho phép lấy safeArea và điều chỉnh padding để không thứ gì chui vào “tai thỏ” của điện thoại.
Ở mức CSS có thể thêm padding bổ sung:
// Pseudo-code
const { top, bottom } = useSafeArea(); // giả sử trả về { top: 8, bottom: 16 }
return (
<div style={{ paddingTop: top, paddingBottom: bottom }}>
{/* nội dung */}
</div>
);
Trong phạm vi bài giảng, điều quan trọng là nguyên tắc: widget phải tôn trọng giới hạn chiều cao và vùng an toàn, nếu không UX sẽ ngay lập tức thành “cuộn thêm ba lần nữa mới thấy nút”.
6. Tailwind và shadcn/ui: đừng “tái phát minh” nút bấm
Tự viết toàn bộ UI bằng CSS thuần giờ gần như là “thể thao hạng nặng”. Trong bối cảnh ChatGPT Apps, dễ hơn nhiều là lấy thư viện đã được kiểm chứng và tinh chỉnh nó theo yêu cầu của nền tảng. Trong khoá học, ta dựa vào Tailwind và shadcn/ui làm stack cơ bản.
Tailwind như “từ điển” khoảng cách và màu sắc
Tailwind cung cấp bộ tiện ích tiện lợi:
- khoảng cách (p-4, gap-3),
- kích cỡ (text-sm, text-base),
- màu (text-muted-foreground, bg-card), vốn trong shadcn/ui và hệ tương tự đã gắn với biến CSS của chủ đề.
Điều này khớp hoàn hảo với yêu cầu của ChatGPT:
- bạn không bịa ra khoảng cách tuỳ tiện,
- đặt cỡ chữ một cách nhất quán,
- không phá màu hệ thống, mà dùng token đã thống nhất sẵn.
shadcn/ui như bộ thành phần gọn gàng
shadcn/ui (và thư viện tương tự) cung cấp sẵn Card, Button, Input, Tabs v.v., đã cấu hình trên chủ đề Tailwind. Điều này tăng tốc đáng kể việc ráp giao diện tối giản, sạch sẽ, đặc biệt cho các thẻ của GiftGenius.
Ví dụ GiftCard dùng shadcn/ui:
// components/GiftCardShadcn.tsx
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
type GiftCardProps = {
title: string;
price: string;
description: string;
};
export function GiftCardShadcn(props: GiftCardProps) {
return (
<Card>
<CardHeader>
<CardTitle className="text-base">{props.title}</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
<p className="text-sm font-medium text-emerald-600">{props.price}</p>
<p className="text-sm text-muted-foreground">{props.description}</p>
<Button className="mt-2">Chọn quà</Button>
</CardContent>
</Card>
);
}
Điều chính yếu ở đây không phải là shadcn, mà là các nguyên tắc:
- tiêu đề không khổng lồ;
- mô tả dễ đọc;
- nút tuân theo hệ thiết kế chung, không “một mình một kiểu”.
Tùy biến cho ChatGPT
Trong dự án thực tế, bạn có thể tinh chỉnh bảng màu theo phong cách tối giản của ChatGPT: nền sáng, bóng nhẹ, bo góc gọn. Kế hoạch module khuyến nghị dựa vào hệ thiết kế sẵn có, thay vì tạo vũ trụ mới.
Cách tiếp cận đơn giản:
- lấy nền tảng shadcn/ui;
- giữ phông hệ thống;
- thiết lập một-hai màu thương hiệu trong token primary / accent;
- đảm bảo cả inline và fullscreen dùng cùng các token đó.
Như vậy bạn có một hạt nhân trực quan nhất quán mà không tốn công thừa.
7. Ngôn ngữ thị giác của GiftGenius: ghép mọi thứ lại
Hãy hệ thống hoá những gì có thể coi là “ngôn ngữ thị giác” cho GiftGenius của chúng ta.
Thứ nhất, bảng màu. Nền và chữ thừa hưởng từ ChatGPT; màu nhấn — không phô trương nhưng đủ nổi, áp dụng cho nút CTA và có thể là badge giảm giá. Ở chủ đề tối, màu nhấn sáng hơn một chút để giữ tương phản.
Thứ hai, kiểu chữ. Phông hệ thống cơ bản, kích cỡ text-sm cho văn bản chính và text-base cho tiêu đề thẻ. Nghiêng và viết hoa toàn bộ dùng hiếm, chỉ khi có lý do. Tiêu đề trong trình hướng dẫn fullscreen cao hơn một bước, nhưng vẫn không “thét” kiểu text-4xl.
Thứ ba, khoảng cách và lưới. Ở inline, danh sách quà — một hoặc hai cột với gap-3/gap-4, mỗi thẻ có p-4. Ở fullscreen — 2–3 cột, các bước của trình hướng dẫn có khoảng trống đủ giữa form và nút. Không có cuộn ngang cho kịch bản chính.
Sơ đồ nhỏ cho các màn hình của GiftGenius:
graph TD A[Inline: danh sách quà tặng] --> B[GiftCard
màu/kiểu chữ/CTA] A --> C[GiftGrid 1–2 cột] D[Fullscreen: trình hướng dẫn chọn quà] --> E[Bước 1
form] D --> F[Bước 2
bộ lọc/khoảng] D --> G[Bước 3
xác nhận] B --> H[GiftButton
điểm nhấn thương hiệu]
Thứ tư, tương thích với ngữ cảnh host. Mọi phần tử cư xử đàng hoàng khi chuyển sáng/tối, tôn trọng maxHeight và không ẩn dưới safe-area. Màu không “tranh” với ChatGPT, còn nút CTA trông giống nhau ở mọi nơi để người dùng nhớ đường bấm theo phản xạ.
Bộ quyết định như vậy đã đủ để ứng dụng của bạn đem đi demo không chỉ cho lập trình viên mà còn cho người dùng thật hay product manager: sẽ có thứ để bàn, ngoài “đây là MCP, kia là Agents SDK”.
8. Khả năng truy cập (Accessibility Guidelines, WCAG AA)
Ta đã lướt qua WCAG khi nói về tương phản chữ và nền trong mục 2.3. Lúc đó ta quan tâm một chỉ dấu thực tiễn — không giết chết khả năng đọc. Giờ nhìn rộng hơn: cùng một giao diện sẽ ra sao với người không nhìn bằng mắt, và với chính ChatGPT ở chế độ thoại.
WCAG AA — là mức tiêu chuẩn truy cập trong bộ quy tắc quốc tế WCAG (Web Content Accessibility Guidelines), mô tả cách làm website và giao diện có thể tiếp cận cho người có hạn chế về thị lực, vận động, nhận thức, v.v.
Ý tưởng chính của WCAG AA — biến giao diện từ “có thể truy cập về mặt lý thuyết” thành thực sự dùng được. Mức này gồm hàng chục yêu cầu ảnh hưởng trực tiếp đến chất lượng tương tác. Trong đó — ngưỡng tương phản chữ/nền khoảng 4.5:1 như đã nói, cũng như yêu cầu về kích thước vùng có thể bấm, trạng thái focus, thông báo lỗi trong form, v.v.
Một lớp riêng — hỗ trợ công nghệ hỗ trợ, gồm các screen reader. Mức AA yêu cầu ngữ nghĩa chính xác: tiêu đề phải là tiêu đề, danh sách là danh sách, nút là nút, và phần tử tương tác phải có role và văn bản thay thế đúng. Điều này cho phép người dùng dùng VoiceOver, TalkBack hay NVDA hiểu đầy đủ cấu trúc và ý nghĩa giao diện.
Screen reader (trình đọc màn hình)
Screen reader (trình đọc màn hình) — là chương trình đọc và/hoặc cấu trúc nội dung trên màn hình, cho phép người có thị lực kém sử dụng máy tính, smartphone hoặc web app.
Nhưng screen reader không chỉ “đọc văn bản thành tiếng”. Nó là một hệ thống tương tác đầy đủ, biến biểu diễn trực quan của trang hoặc app thành một điều hướng bằng âm thanh và có cấu trúc có thể tiếp nhận.
ChatGPT, screen reader và WCAG AA
Nếu widget của bạn được đánh dấu theo nguyên tắc WCAG AA (role đúng, tiêu đề, nhãn nút rõ ràng), nó không chỉ dễ hiểu với screen reader mà còn với ChatGPT ở chế độ thoại. Người dùng nói chuyện với ChatGPT bằng giọng nói, còn mô hình, dựa trên cùng cấu trúc ngữ nghĩa đó, có thể “ảo hoá” thao tác của con người: tìm phần tử, bấm nút, đi theo liên kết, v.v.
Theo yêu cầu của ChatGPT Store, hỗ trợ chuẩn WCAG AA là bắt buộc cho mỗi ứng dụng. Mỗi widget và mỗi công cụ cần có mô tả chi tiết, chất lượng; và phần markup — phải tuân chuẩn WCAG AA: ngữ nghĩa đúng, nhãn dễ đọc, trạng thái dự đoán được.
Vì vậy yêu cầu WCAG AA không phải “tính năng cho người đặc thù”, mà là nguyên tắc thiết kế nền tảng để ChatGPT Apps có thể làm việc trọn vẹn với ứng dụng của bạn, kể cả khi người dùng tương tác bằng giọng nói.
Các kịch bản voice‑UX, khác biệt giữa đối thoại giọng nói và văn bản, và yêu cầu của ChatGPT Store sẽ còn trở lại — ở bài học khác của module này và module về xuất bản App. Nhưng tất cả đứng trên nền tảng mà bạn vừa thấy: chế độ giọng nói = đa phương thức + khả năng truy cập (WCAG AA + screen reader).
9. Lỗi thường gặp trong thiết kế trực quan ChatGPT App
Lỗi №1: Hard-code nền trắng/đen và màu chữ.
Lập trình viên vẽ nền trắng và chữ đen mà không nghĩ đến chủ đề tối. Ở chủ đề sáng còn tạm, còn chủ đề tối — thành đèn pha và phá UX. Đúng hơn là dùng màu hệ thống và chủ đề của host (biến CSS, prefers-color-scheme hoặc API của Apps SDK), còn màu riêng giữ cho điểm nhấn.
Lỗi №2: Thương hiệu quá “gắt”.
Xuất hiện nền gradient chói, phông custom, viền sặc sỡ. Widget trông như banner promo chứ không phải phần của ChatGPT. Hướng dẫn yêu cầu ngược lại: tối giản, “bản địa”, dùng màu thương hiệu khéo léo ở phần tử chủ chốt, ví dụ nút chính.
Lỗi №3: Không có phân cấp kiểu chữ.
Tất cả chữ cùng cỡ và độ đậm, hoặc ngược lại — ba cấp tiêu đề trên một thẻ nhỏ, lại còn viết hoa. Người dùng không biết cái gì quan trọng: tên, giá hay mô tả. Tốt hơn là thống nhất 3–4 cấp và giữ chúng ở mọi nơi: tiêu đề, tham số chính, văn bản chính, chú thích.
Lỗi №4: Phần tử dính vào nhau, thiếu khoảng thở.
Thẻ dí sát nhau, văn bản sát mép, nút sát chữ. Trên desktop còn chịu được, trên di động thành nhiễu thị giác. Nên dùng một thang khoảng cách thống nhất (ví dụ các lớp Tailwind p-4, gap-3) và đừng tiết kiệm “không khí”.
Lỗi №5: Cố nhét 4–5 cột ở chế độ inline.
Lập trình viên vẫn nghĩ như trang e-commerce và làm lưới 4 cột hẹp trong chat. Trên màn hình rộng còn tranh cãi, trên di động — không thể đọc, lại thêm cuộn ngang. Trong inline thường 1–2 cột là đủ; cột thứ ba để cho fullscreen.
Lỗi №6: Bỏ qua giới hạn chiều cao và safe‑area.
Widget vẽ danh sách khổng lồ không có cuộn bên trong và không tính maxHeight, khiến nút nằm “dưới đáy màn hình”. Hoặc phần tử ẩn sau phần khuyết trên di động. Hãy dùng dữ liệu về chiều cao tối đa và vùng an toàn để phân bổ chiều cao và padding hợp lý.
Lỗi №7: Nút và thẻ không nhất quán giữa inline và fullscreen.
Ở inline, nút xanh lá và bo tròn; ở fullscreen — xanh dương và vuông. Người dùng mất cảm giác một sản phẩm thống nhất. Cần đưa các style cơ bản của nút và thẻ vào component/chủ đề chung và dùng ở mọi chế độ.
Lỗi №8: Phông “tác giả” và trang trí quá đà.
Nhúng webfont nặng “cho đẹp” phá tính nhất quán với ChatGPT và đôi khi làm giảm hiệu năng. Khuyến nghị của nền tảng là dùng phông hệ thống và kiểu chữ gọn gàng. Nếu rất muốn thể hiện như nhà thiết kế — hãy đầu tư vào icon và microcopy, đừng “cách mạng phông chữ”.
GO TO FULL VERSION