Refactoring UI: Những Nguyên Tắc Thiết Kế Giao Diện Mà Mọi Developer Nên Biết
“Design không phải là làm cho thứ gì đó trông đẹp. Design là làm cho thứ gì đó hoạt động đúng cách.”
Là một developer, tôi từng nghĩ thiết kế UI là lãnh địa riêng của designers. Nhưng thực tế là: mọi người viết code đều phải đưa ra quyết định thiết kế hàng ngày — từ việc đặt khoảng cách cho một button, chọn màu cho một badge, cho đến bố cục của một form đăng ký. Refactoring UI là cuốn sách giúp developers tư duy đúng về những quyết định đó.
1. STARTING FROM SCRATCH
Bắt đầu từ Feature, không phải Layout
Khi bắt tay vào thiết kế một ứng dụng, hầu hết chúng ta đều nghĩ ngay đến:
- Ứng dụng trông sẽ như thế nào?
- Bố cục sẽ ra sao?
- Có cần top nav không?
Nhưng thực ra chúng ta đang chỉ nghĩ về phần vỏ bên ngoài. Một ứng dụng thực chất chỉ là tập hợp các features. Trước khi thiết kế một feature mà chưa có bất cứ thông tin gì về cách thức vận hành của nó, đây là công thức cho sự… mất phương hướng.
Thay vì bắt đầu ở phần vỏ, hãy bắt đầu với những thành phần thực sự của một feature.
Ví dụ: Với service booking flight, bắt đầu với feature “tìm kiếm chuyến bay”. Giao diện cần:
- Fields cho điểm đi, điểm đến
- Fields cho ngày đi, ngày trở về
- Button thực thi chức năng search
Và chỉ vậy thôi. Không cần quan tâm đến navigation, sidebar, hay footer ở giai đoạn này.
Chi tiết đến sau
Một tip hay: Design trên giấy bằng bút Sharpie.

Việc vẽ chi tiết bằng bút Sharpie là điều không thể — nên đây là cách hay để bỏ thói quen đi quá sâu vào chi tiết ngay từ đầu thiết kế.
Giữ màu Grayscale lúc đầu
Ban đầu nên thiết kế với 2 màu đen, trắng (grayscale) — điều này buộc bạn phải chú trọng vào khoảng cách, tương phản, kích thước. Kết quả là bạn sẽ có được giao diện với tính phân cấp tốt trước, rồi mới thêm màu sắc vào sau.
Đừng đầu tư quá sớm
Build nhanh nhất có thể. Mục đích của bản thiết kế ban đầu là thể hiện ý tưởng — không phải là sản phẩm cuối. Khi đã có quyết định cuối cùng, hãy bỏ bản thô ban đầu và làm lại đúng cách.
Chọn tính cách (Personality) cho giao diện
Mỗi site nên có đặc điểm nhận dạng riêng. Những site liên quan đến ngân hàng hướng đến bảo mật, tin cậy, chuyên nghiệp, trong khi startup có thể mang lại hình ảnh vui nhộn, tươi mới.
Tính cách được quyết định bởi:
Font choice:
- Serif (có chân): sang trọng, cổ điển
- Rounded sans-serif (tròn): vui nhộn, trẻ trung
- Neutral sans-serif (không chân trung tính): đơn giản, hiện đại
Màu sắc:
- Xanh nước biển: an toàn, thân thiện
- Vàng kim: đắt đỏ, tinh vi
- Hồng: vui nhộn, không căng thẳng
Border radius:



Điểm mấu chốt: chỉ sử dụng một loại nút duy nhất để tạo sự thống nhất.
Giới hạn lựa chọn của bạn
Khi có quá nhiều lựa chọn (opacity 10% hay 15%? margin 18px hay 20px?), quyết định trở nên cực kỳ khó khăn dù không có lựa chọn nào thực sự tồi.
Giải pháp: Xây dựng Design System từ trước.
Đừng tìm màu mới mỗi khi thiết kế UI mới — hãy định nghĩa sẵn 8-10 màu chuẩn:

Đừng chỉnh từng pixel cho đến khi font chữ “hoàn hảo” — hãy tự thiết kế một hệ thống font size ngay từ đầu:

Việc này mất thời gian lúc đầu, nhưng mỗi khi thêm UI mới, bạn sẽ không cần phải ra quyết định lại từ đầu.
2. HIERARCHY IS EVERYTHING
Không phải mọi element đều bình đẳng
Visual Hierarchy là khái niệm chỉ sự phân cấp giữa các thành phần trong UI. Nếu không có sự phân cấp, mọi thứ cạnh tranh với nhau, tạo ra một bức tường thông tin rối rắm.
Đây là giao diện không có sự phân cấp:

Và đây là giao diện đã có sự phân cấp thông tin — dù font chữ và tông màu không thay đổi gì:

Kích thước không phải tất cả
Sai lầm phổ biến: primary content phải có font size lớn, secondary content có font size nhỏ. Nếu có 4-5 cấp phân cấp thì phải dùng 4-5 font size — nhưng trong một site chỉ nên dùng tối đa 3 font sizes.
Thay vào đó, kết hợp nhiều yếu tố:

Trong một site chỉ cần:
- 2-3 màu: Dark cho primary (tiêu đề), Grey cho secondary (ngày tháng), Lighter grey cho cấp 3 (copyright)
- 2 font weights: 400-500 cho text thường, 600-700 cho nội dung muốn nhấn mạnh
Đừng dùng grey text trên background màu
Light grey text trên background trắng hoạt động hoàn hảo. Nhưng điều này không đúng với background màu:

Cách đúng: dùng màu text gần với màu background (cùng tông):

Chọn màu dựa theo background color rồi chỉnh độ sáng:

Nhấn mạnh bằng cách làm mờ xung quanh
Đôi lúc muốn nhấn mạnh một item nhưng không thể làm nó nổi hơn được nữa:

Thay vì cố làm active item nổi bật hơn, hãy làm mờ (de-emphasize) các item xung quanh:

Có thể áp dụng cho những phần UI lớn hơn — ví dụ bỏ background của sidebar để nội dung chính nổi bật:

Label: Dùng khi thực sự cần
Hầu hết chúng ta mắc bẫy hiển thị dữ liệu theo format label: value. Điều này khiến người đọc khó nắm bắt thông tin vì không có bất cứ hệ thống phân cấp nào.
Đôi khi không cần label: abc@mail.com → ai cũng biết đó là email. Ngữ cảnh đã nói lên tất cả:

Kết hợp label và value: Thay vì “In stock: 12”, hãy viết “12 in stock” — làm nổi bật value:

Label là secondary: Khi cần label (như dashboard), hãy coi label như supporting content — de-emphasize chúng, làm nổi bật dữ liệu:

Phân cấp thị giác ≠ Phân cấp tài liệu
Chúng ta được dạy rằng <h1>, <h2> phải có kích cỡ lớn. Nhưng trong nhiều trường hợp, title chỉ đóng vai trò như label — nội dung mới là thứ người ta cần đọc:

Đừng để element đang sử dụng làm ảnh hưởng đến việc style cho thiết kế.
Dùng Contrast để bù cho Weight
Khi kết hợp text và icon, icon thường nổi bật hơn text (đặc biệt solid icons). Cách xử lý: dùng màu nhạt hơn cho icon thay vì thay đổi weight:

Tương tự, có thể tăng weight của border để bù cho contrast thấp. Border mỏng màu nhạt trông không có nghĩa, nhưng làm tối màu sẽ khiến người dùng tập trung vào border thay vì nội dung:


Semantics là thứ yếu
Chúng ta hay mắc bẫy thiết kế actions theo semantics mà quên đi tính kế thừa. Trong trang web thường có 1 main action, 2 secondary actions, và một vài tertiary actions.
Nếu thiết kế theo semantics:

Thiết kế đúng theo phân cấp:

- Primary actions: Background tương phản cao, solid
- Secondary actions: Outline style hoặc màu tương phản thấp
- Tertiary actions: Style như một link
Actions liên quan đến xóa không có nghĩa là mặc nhiên primary action. Nếu không phải primary action, nút xóa nên là secondary hoặc tertiary — không phải lúc nào cũng cần background đỏ to tướng.

Chỉ khi nút xóa đi kèm với bước xác nhận thì nó mới nên là primary action.
3. LAYOUT AND SPACING
Bắt đầu với quá nhiều White Space
Một trong những cách đơn giản nhất để clean up thiết kế: thêm nhiều không gian thở hơn cho các elements.

White space nên bị xóa, không phải được thêm
Khi thiết kế trông chật chội, chúng ta thường thêm margin/padding — nhưng không gian được thêm thường quá ít nên không cải thiện gì mấy.
Cách tiếp cận tốt hơn: bắt đầu với thiết kế có nhiều khoảng trắng, sau đó thu hẹp dần cho đến khi cảm thấy ổn:

Dense UIs cũng có chỗ đứng
Giao diện dashboard (Dense UI) mang lại cảm giác bận rộn nhất định — và đó không nhất thiết là xấu. Với những giao diện loại này, không cần quá nhiều khoảng trắng:

Xây dựng hệ thống Spacing
Thay vì căn chỉnh từng pixel một, hãy xây dựng hệ thống spacing từ trước.
Tại sao linear scale không hoạt động? Với elements nhỏ, thay đổi 2px cũng tạo ra sự khác biệt ~25%. Nhưng với elements lớn như card, thay đổi 20px chỉ tạo khác biệt ~2%.

Xây dựng hệ thống: Dùng base 16px (default font size của trình duyệt) làm cơ sở. Các kích cỡ lớn hơn là bội số của 16px:

Khi có hệ thống spacing, thiết kế sẽ nhất quán và trôi chảy hơn bao giờ hết:

Đừng cố lấp đầy toàn bộ màn hình
Hiện nay chúng ta thường dùng công cụ thiết kế có canvas rộng 1200-1400px. Nhưng có nhiều không gian không có nghĩa phải dùng hết:

Nếu element chỉ cần 600px thì hãy chỉ dùng 600px:

Navigation full-width không có nghĩa là mọi element khác cũng phải vậy:

Thu nhỏ canvas: Nếu thiết kế web responsive, hãy bắt đầu từ mobile (400px). Khi hài lòng với mobile, tăng kích cỡ canvas và chỉnh sửa nhỏ:


Thinking in columns: Khi thiết kế phù hợp màn hình nhỏ nhưng mất cân bằng trên màn hình rộng, hãy chia thành nhiều cột thay vì chỉ kéo rộng ra:


Grid bị đánh giá quá cao
12-column grid rất phổ biến nhưng không phải lúc nào cũng phù hợp.
Vấn đề với percentage-based grid: Sidebar 25% + MainContent 75%. Khi resize màn hình, sidebar cũng resize theo — có thể rộng hơn cần thiết hoặc nhỏ đến mức text bị vỡ:

Giải pháp tốt hơn: Sidebar dùng fixed width, MainContent flexible với internal grid:

Don’t force shrink: Với login card, thay vì phụ thuộc vào grid (6/12 columns), hãy định nghĩa max-width và chỉ force shrink khi màn hình nhỏ hơn max-width:


Relative sizing không scale được
Giả sử: body font size 18px, title font size 45px → tỉ lệ 2.5. Liệu điều này có phù hợp khi màn hình nhỏ đi?
Với màn hình nhỏ (body 14px), nếu giữ nguyên tỉ lệ → title 35px:

Nếu chỉnh title xuống 24px:

Tương tự, với button: nếu giữ nguyên tỉ lệ padding/font-size khi scale:

Nếu thay đổi không theo tỉ lệ cứng:

Tránh Spacing mơ hồ
Khi thiết kế, spacing và separators là công cụ để phân biệt các element groups với nhau.
Khi margin giữa label với input bằng nhau — không có sự liên kết giữa label và input cùng group:

Khi thay đổi khoảng cách giữa input với label phía dưới, mọi thứ có sự liên kết rõ ràng hơn:

Tương tự trong article: section heading cần khoảng cách phía trên đủ lớn:


Điều tương tự cũng xảy ra với các phần tử nằm ngang:

Khoảng cách xung quanh group elements luôn phải lớn hơn khoảng cách bên trong group.
4. DESIGNING TEXT
Thiết lập Type Scale
Không quá khó để tìm thấy một thiết kế có quá nhiều font-size:

Chọn font-size mà thiếu đi tính hệ thống là ý tưởng tồi vì:
- Khiến giao diện thiếu tính thống nhất
- Làm giảm tiến độ công việc
Modular scales (tính toán theo tỉ lệ như 4:5, 2:3, 1:1.618) nghe hay nhưng không thực tế: thường cho ra số phân số và không đủ font-sizes cần thiết cho interface design.
Hand-crafted scales mới là cách đúng — tự tạo hệ thống để chủ động kiểm soát:


4. DESIGNING TEXT (tiếp theo)
Tránh đơn vị em
Không nên dùng đơn vị em vì nó là giá trị mang tính tương đối — em của nested elements phụ thuộc vào element cha. Điều này dẫn đến việc tạo ra các giá trị ngoài ý muốn:

Hãy sử dụng
pxhoặcremđể bảo toàn những gì đang xây dựng cho giao diện.
Chọn Font tốt
Một vài tricks để chọn fonts phù hợp:
- Play it safe: Sans-serif luôn là lựa chọn an toàn. Nếu không tin vào cảm nhận của bản thân, hãy dùng system font stack:
-apple-system,Segoe UI,Roboto,Noto Sans,Ubuntu,Cantarell,Helvetica Neue. - Ignore typefaces với ít hơn 5 weights: Fonts có nhiều weights thường được tạo ra cẩn thận hơn.
- Optimize for legibility: Fonts cho headlines có khoảng cách giữa các chữ hẹp hơn fonts cho text nhỏ.

- Steal from people who care: Tìm một site bạn yêu thích, inspect để xem họ dùng font gì.
Giữ Line Length trong tầm kiểm soát
Line length lý tưởng: 45-75 ký tự mỗi dòng, tương đương chiều rộng 20-35em.

Khi kết hợp paragraph với ảnh hoặc components lớn, vẫn nên giữ chiều rộng của paragraph trong khoảng hợp lý dù layout rộng hơn:


Căn lề theo Baseline, không phải Center
Khi kết hợp nhiều font sizes trong cùng một dòng, căn lề dọc theo center sẽ trông vụng về:

Thay vào đó, căn theo baseline (đường kẻ chân chữ):

Line-height tỉ lệ nghịch với Font Size
Line-height 1.5 là điểm khởi đầu tốt, nhưng cần điều chỉnh theo:
Chiều rộng dòng: Paragraph hẹp cần line-height: 1.5, paragraph rộng cần line-height: 2.

Font size: Font nhỏ cần line-height cao hơn, font lớn (headline) chỉ cần line-height: 1.

Line-height và font size tỉ lệ nghịch với nhau.
Không phải Link nào cũng cần màu sắc đặc biệt
Với giao diện chỉ toàn links, việc làm nổi bật bằng màu xanh truyền thống tạo ra sự gượng ép:

Thay vào đó dùng font weight đậm hơn và màu tối hơn:

Với những links không quan trọng, chỉ thêm underline hoặc màu khi hover.
Căn lề có chủ đích
- Căn giữa (center): Tốt cho headlines hoặc text blocks ngắn độc lập.

- Đừng center long-form text: Nếu text dài hơn 2-3 dòng, hãy căn trái.

- Căn phải số liệu trong bảng: Giúp so sánh nhanh hơn.

Letter-spacing hiệu quả
- Tightening headlines: Nếu dùng font có letter-spacing rộng cho headline, hãy thu hẹp lại.
- Improving all-caps: Với text viết HOA toàn bộ, các chữ có cùng chiều cao nên tăng letter-spacing để dễ đọc hơn.
5. WORKING WITH COLOR
Dùng HSL thay vì Hex
Hex và RGB không trực quan khi đọc code. HSL biểu diễn màu qua 3 thuộc tính gần với thị giác con người:
- Hue (0-360°): Vị trí trên bánh xe màu — 0° là đỏ, 120° là xanh lá
- Saturation (0-100%): 0% là xám, 100% là sống động
- Lightness (0-100%): 0% là đen thuần, 50% là màu hue nguyên chất, 100% là trắng

Bạn cần nhiều màu hơn bạn nghĩ
Cách phổ biến là chọn 1 màu chủ đạo + palette generator tạo ra 4 màu thêm. Thực tế không đủ dùng.
Bạn cần chia bảng màu thành 3 nhóm:
Grey (8-10 shades): Cho text, backgrounds, panels, form controls. Bắt đầu từ dark grey thay vì true black:

Primary color (5-10 shades): Màu nhận diện thương hiệu. Ultra-light shades dùng cho alert backgrounds, darker shades dùng cho text:

Accent colors: Màu thu hút sự chú ý, plus màu cho các states:
- Đỏ cho destructive actions
- Vàng cho warnings
- Xanh cho positive trends

Xây dựng Shades từ trước
Đừng dùng các tên màu như “darker” hay “lighter” — sẽ tạo ra mớ bùng nhùng. Hãy tạo một tập cố định các shades (thường là 9 shades từ 100 đến 900):
- Chọn base color phù hợp làm button background
- Tìm darkest shade (dùng cho text) và lightest shade (dùng cho background)
- Điền các shades ở giữa theo nguyên tắc tăng dần

Lightness làm mất Saturation
Trong HSL, khi lightness gần 0% hoặc 100%, ảnh hưởng của saturation giảm. Muốn shades lighter/darker trông rõ ràng, hãy tăng saturation khi lightness ra xa 50%.
Ngoài ra, có thể thay đổi độ sáng bằng cách xoay hue thay vì chỉ thay đổi lightness:
- Muốn màu sáng hơn: xoay về phía 60°, 180°, 300° (các hues sáng)
- Muốn màu tối hơn: xoay về phía 0°, 120°, 240° (các hues tối)
Đừng xoay hue quá 20-30° nếu không muốn có một màu hoàn toàn khác.
Grey không nhất thiết phải là Grey
Grey trong thực tế thường có saturation khá mạnh. Saturate grey với một chút màu tạo ra cảm giác ấm/mát:
- Saturate với xanh: Grey mát hơn, nhẹ nhàng hơn
- Saturate với vàng/cam: Grey ấm áp hơn
Accessibility: Tương phản không nhất thiết phải xấu
Normal text (dưới 18px) cần tỉ lệ tương phản ít nhất 4.5:1, text lớn cần 3:1.
Khi cần đảm bảo tương phản mà không muốn dùng text trắng trên background tối, hãy đảo ngược: dùng text màu đậm trên background màu nhạt hơn.
Ngoài ra, đừng chỉ dựa vào màu sắc để truyền thông tin — thêm icons hoặc labels để hỗ trợ người dùng có thị giác màu kém.
6. CREATING DEPTH
Mô phỏng nguồn sáng
Trong thực tế, ánh sáng đến từ phía trên. Hãy áp dụng nguyên tắc này vào thiết kế:
- Raised elements (nổi lên): Cạnh trên sáng hơn cạnh dưới, có box-shadow ngắn phía dưới.

- Inset elements (lõm xuống): Dùng inset box-shadow phía trên và border sáng phía dưới.

Dùng Shadow để diễn đạt độ cao (Elevation)
Shadow nhỏ → element chỉ cao hơn một chút. Shadow lớn → element gần người dùng hơn:
- Small shadow: Card bình thường
- Medium shadow: Dropdown, popover
- Large shadow: Dialog/Modal
Xây dựng elevation system với 5 levels shadow, tương tự như font/color system:

Shadow cũng có thể dùng để diễn đạt tương tác — item được kéo thả sẽ có shadow lớn hơn, button được nhấn sẽ có shadow nhỏ đi.
Shadow thường có 2 phần
Shadow chuyên nghiệp thường gồm:
- Phần lớn: blur lớn, mô phỏng shadow từ luồng sáng trực tiếp
- Phần nhỏ: blur nhỏ hơn nhưng tối hơn, mô phỏng shadow vùng ánh sáng không chạm tới

Flat design cũng có chiều sâu
Ngay cả flat design cũng có thể tạo cảm giác chiều sâu:
- Màu sáng hơn → cảm giác gần người dùng hơn
- Solid shadow (không blur): tạo cảm giác nổi mà vẫn giữ tính phẳng
Overlap Elements để tạo layers
Di chuyển card để nằm ở vùng chuyển giao giữa 2 backgrounds khác nhau sẽ tạo cảm giác đa tầng:

7. WORKING WITH IMAGES
Text cần Contrast nhất quán
Khi đặt text lên background là ảnh, vấn đề không nằm ở màu của text mà ở bức ảnh — ảnh có cả vùng sáng và vùng tối, text trắng sẽ bị chìm ở vùng sáng:

Giải pháp:
- Semi-transparent overlay: Tráng lớp tối lên ảnh để giảm tương phản
- Giảm contrast + tăng brightness: Làm giảm tính sáng tối vốn có
- Colorize ảnh: Giảm contrast → desaturate → thêm solid fill với multiply blend mode
- Text shadow: Blur radius lớn, không có offset
Icon không nên Scale up
Scale up SVG icon 3-4x so với intended size sẽ mất đi tính cân xứng. Thay vào đó, bao icon bởi một shape có background color phù hợp:

Screenshot không nên Scale down
Thu nhỏ screenshot 70% khiến font size thực tế xuống còn 4px — người dùng phải nheo mắt. Giải pháp:
- Chụp ở layout nhỏ hơn (tablet)
- Chỉ chụp khu vực trung tâm của feature
- Tạo simplified version thay thế bằng cách thay text bằng lines đơn giản
Beware User-Uploaded Content
- Dùng
background-size: coverđể kiểm soát tỉ lệ ảnh upload của người dùng - Dùng inner box-shadow nhẹ thay vì border để tránh “bleed” khi ảnh cùng màu với background
8. FINISHING TOUCHES
Supercharge the Defaults
Thay vì thêm chi tiết mới, hãy tận dụng tối đa những gì đang có:
- Bullet list → dùng icons thay vì dấu chấm
- Quote → tăng font size, thay đổi màu
- Links → font weight đậm hơn, underline style độc đáo
- Checkbox → dùng màu nhận diện thương hiệu thay vì màu mặc định browser
Thêm màu bằng Accent Borders
Một trick đơn giản: thêm accent border màu sắc vào UI:
border-topcủa Cardborder-bottomcủa active navigation itemborder-leftcủa alert message- Accent ngắn phía dưới headline

Trang trí Background
Nếu thiết kế trông đơn điệu dù hierarchy, spacing và typography đều tốt:
- Thay đổi background color cho một section
- Gradient nhẹ: Dùng 2 hues không khác nhau quá 30 độ
- Repeating pattern: Dùng HeroPattern
- Thêm geometric shapes/illustrations
Giữ độ tương phản giữa pattern và background ở mức thấp để đảm bảo tính dễ đọc.
Đừng bỏ qua Empty States
Khi nội dung phụ thuộc vào dữ liệu từ người dùng, trang sẽ có lúc trống. Đừng để trống — dùng illustrations để thu hút và khuyến khích người dùng hành động:
Empty state là tương tác đầu tiên của người dùng với sản phẩm. Hãy coi đó là cơ hội để tạo ấn tượng.
Dùng ít Border hơn
Border làm người dùng tập trung vào nó thay vì nội dung. Thay thế bằng:
- Box-shadow nhẹ: Phân cách tinh tế
- Hai background colors khác nhau: Các phần tử cạnh nhau khác background color
- Extra spacing: Tăng khoảng cách giữa các group
Think Outside the Box
Hãy phá vỡ “định kiến” về cách một component phải trông như thế nào:
- Dropdown có thể multi-column với icons thay vì list đơn giản
- Table có thể kết hợp columns liên quan, thêm ảnh/màu sắc
- Radio buttons có thể là selectable cards thay vì vòng tròn nhàm chán
Lời Kết
Sau khi đọc hết Refactoring UI, tôi nhận ra design là một kỹ năng có thể học được — không phải tài năng bẩm sinh. Các quyết định thiết kế đều có thể tư duy hóa thành nguyên tắc rõ ràng:
- Xây dựng hệ thống trước: Màu, font, spacing — định nghĩa một lần, dùng mãi mãi
- Visual Hierarchy là nền tảng — không phải màu sắc hay animation
- White space là tài sản, không phải không gian lãng phí
- Scale độc lập — không có tỉ lệ nào là bất biến cho mọi màn hình
- De-emphasize đôi khi hiệu quả hơn emphasize
- Ánh sáng và shadow tạo ra chiều sâu — hãy mô phỏng vật lý thực tế
- Đừng để màu sắc là thứ duy nhất truyền thông tin — accessibility quan trọng
- Phá vỡ định kiến về cách components phải trông như thế nào
Đây là cuốn sách ngắn nhưng mỗi trang đều có thể áp dụng ngay vào dự án thực tế.
Bài viết được tổng hợp từ: Refactoring UI — Adam Wathan & Steve Schoger (2019). Nội dung gốc tham khảo từ bài viết của tuananhhedspibk.