Hai cách giải cùng một vấn đề: CSS không có scope, nên phải quy ước để tránh tên class đụng nhau và style rò rỉ.
BEM — block__element--modifier, mỗi class một tầng ý nghĩa:
- Specificity phẳng (một class), dễ đoán thứ tự đè.
- HTML sạch, tên class mô tả vai trò, dễ đọc khi review.
- Đổi lại: file CSS chỉ tăng, hiếm khi giảm — không ai dám xoá vì không rõ còn dùng ở đâu. Nhảy qua lại giữa file markup và file CSS. Đặt tên thành gánh nặng thật.
Utility-first — ghép sẵn class một-mục-đích:
- Không phải đặt tên, không phải mở file khác; xoá component là xoá luôn style.
- CSS đầu ra gần như đứng yên khi codebase lớn dần vì các utility được dùng lại.
- Đổi lại: class list dài, khó đọc; token bị neo vào cấu hình Tailwind; lặp lại chuỗi utility ở nhiều nơi nếu không tách component.
Cách trả lời thực dụng: phụ thuộc vào việc UI đã được component hoá chưa. Có React/Vue thì bản thân component đã lo tái sử dụng, utility bù đúng khoảng trống còn lại và tránh chi phí đặt tên. Còn dự án render server, template nhiều nơi dùng chung, không có lớp component thì BEM (hoặc CSS Modules) giữ trật tự tốt hơn.
Thực tế nhiều team dùng lai: utility cho spacing/layout hằng ngày, class có tên cho vài component phức tạp lặp nhiều lần.