Bem nhau là gì

Đặt tên là 1 trong những vấn đề đau đầu nhất trong khoa học, đặt tên class hay biến, hàm... trong lập trình web của chúng ta cũng vậy. Trước đây thì việc đặt class khá tự do và không có quy chuẩn nào chung, nhưng từ khi BEM ra đời, mọi thứ đã khác đi. Tuy nhiên với ai mới tiếp cận BEM thì chắc chắn sẽ có những băn khoăn, mình viết bài này để giới thiệu 1 số vấn đề mà mình hiểu, mọi người hãy góp ý nếu thấy gì chưa đúng để cùng tìm ra cách sử dụng BEM hợp lý nhất nhé.

BEM là gì và cách dùng?

BEM gồm 3 phần. Block-Elements-Modifiers:

Blocks : là thành phần độc lập về mặt chức năng và logic của trang web, block có thể lồng trong nhau và được lặp lại

Elements: là các thành phần con trong block

Modifiers: bạn hãy hiểu là chúng ta có 1 số kiểu button trong 1 trang web, đa số là màu xanh, ta sẽ cho button mặc định màu xanh, với trường hợp button màu đỏ, ta sẽ thêm hậu tố để phân biệt

Các đặt tên theo BEM sẽ như thế này: .block__element--modifier

Cách chia block thì các bạn hãy để ý các page, chia page ra thành các phần riêng biệt có thể tái sử dụng ở nhiều nơi cả trong 1 page và nhiều page, nếu nó chỉ có trong 1 page thì có thể đặt tên theo page đó còn nếu nó dùng chung cho nhiều page thì hãy tìm 1 cái tên chung chung, ví dụ block text-box chỉ có trong page giới thiệu thì có thể đặt nó là "text-box-intro" sẽ dễ hình dung, còn nếu nhiều page có cái text-box tương tự thì hãy đặt là "text-box" mà thôi.

  1. Elements: Nhiều người mới tiếp cận sẽ thắc mắc, ta có 1 block, trong có element, trong element lại có thành phần con nữa, thì chả lẽ lại đặt là block__element1__element2 ? Câu trả lời là không nên, sau khi chúng ta đã xác định được block trong trang web, tất cả những phần tử con bên trong block đều nên đặt theo block chứ ko phải đặt từ ngoài vào trong. Nên chúng ta sẽ đặt như này: block__element1, block__element2

Ví dụ ta có block giới thiệu phim đang hot như này, giả sử đặt là film-hot đi

, phần khoanh vàng là 1 element: box-info, mọi người có thể đặt là film-hot__box-info. Trong box-info có các element như title phim mình khoanh đỏ, rating..., lúc này chúng ta sẽ đặt là film-hot__title. Các element chỉ cần thể hiện mối quan hệ với block, không cần ràng buộc với thành phần cha bao nó

Bây giờ chúng ta có 2 nút thế này, cùng background-color, cùng text-color, font, cùng border-radius. Và hầu hết các nút đều có height như nút to, vậy thì chúng ta sẽ đặt 1 block là "btn" với height "cao", font, color, border... mặc định. Khi cần sử dụng tới button nhỏ, chúng ta sẽ đặt là "btn btn--small" và css height khác đi đè lên. Tuy nhiên chúng ta cũng có thể đặt là "btn--small" thôi, lúc này các bạn phải css cho btn--small các thuộc tính base như của bth và btn mặc định các bạn sẽ không đặt height nữa, chỉ css những gì chung giữa các nút mà thôi, mình thì hay sử dụng cách 1 và đó cũng là cách được dùng phổ biến hơn, cách này các bạn cũng có thể css btn chỉ những gì chung nhất, không set height mặc định nữa dù đa phần các nút có height giống nhau. Các bạn nên nhớ là việc đặt class không có đúng hay sai, làm sao cho team làm việc thuận lợi nhất có thể là được.

Tuy nhiên thì nó sẽ có vấn đề như này, các nút có height nhỏ chỉ xuất hiện trong trang giới thiệu, còn nút to chỉ xuất hiện trong trang detail, thì lúc này sẽ có 1 cách khác tường minh hơn là các bạn hãy đặt 1 class cha lên tận body hoặc main gì đó to nhất, page-intro và page-detail, lúc này hãy css từ tận page này xuống btn thay vì thêm "--" vào sau btn, người xem sẽ hiểu là "à, cái nút này nó khác là do nằm trong page này". Nếu đó là mục đích khi design thì các bạn nên làm theo cách này, nó sẽ tường minh hơn. Còn nếu các nút thay đổi không phải theo page mà do mục đích ví dụ nút edit thì màu xanh da trời còn nút xóa thì màu đỏ thì các bạn cũng có thể đặt là "btn btn--edit" và "btn--delete" na ná như bootstrap: "btn-warning" đó.

Ví dụ phần phim lẻ mới cập nhật này, hẳn là sẽ có người chia từng phim khoanh vàng thành 1 block, nhưng lại thấy cái bao ngoài giống hệt phần phim bộ phía dưới, chẳng lẽ ta sẽ cho cả phần bao là 1 block và đặt là movie-list -> movie-list__item -> movie-list__title-item [để phân biệt với title của list phim], movie-list__thumbnail-item....? Theo mình thì không nên làm như vậy, BEM nên đặt theo block nhỏ nhất mà đủ bao quát những cái chung và dễ dàng tùy biến. Nếu ta chọn block quá bao quát, quá to, tên các element trong cùng sẽ rất lộn xộn như ví dụ trên. Hãy chia từng phim khoanh vàng là 1 block và cho vào 1 div cha là "movie-list", movie-list sẽ được dùng chung cho cả phần phim bộ phía dưới vì nó tương đồng. Kết quả sẽ như này: movie-list -> movie-item -> movie-item__title, movie-item__sub-title, movie-item__time... Các bạn hãy nhớ rằng BEM là cách đặt tên theo block chứ không phải từ ngoài vào trong, hãy nhìn từ phần tử nhỏ nhất ngược trở ra thay vì cố gắng đặt class từ ngoài vào trong, mình thấy nhiều bạn cố gắng đặt như này: page -> page__wrap -> page__content -> page__content-title, page__content-main. Không nên làm thế, chúng ta không nhất thiết phải sử dụng BEM mọi lúc mọi nơi, chỉ nên sử dụng khi có block, thay vì đặt như trên chúng ta hãy đặt như này: page -> page-wrap -> page-content -> page-title... do page chẳng thể nào là 1 block, các thành phần con của nó không cần đặt theo BEM, tất nhiên đặt cũng chả sao nhưng nó sẽ gặp vấn đề nếu trong cái page__content-main lại có title và nhiều thứ khác, các bạn sẽ đặt theo BEM sao đây?

Kết luận

BEM là 1 quy chuẩn đặt tên class chung tuy nhiên các bạn đừng cố áp đặt mọi thứ phải theo BEM, hãy nghĩ thoáng 1 chút nếu không các bạn sẽ mất rất nhiều thời gian đắn đo để đặt tên. Chỉ cần nhớ rằng hãy đặt tên theo block nhỏ nhất có thể, chứ đừng đặt tên từ ngoài vào trong. 1 block hợp lý là 1 block chỉ có block, các con block__element. BEM sẽ tốt khi chúng ta dùng với SCSS, còn nếu bạn chỉ css thường thì cũng nên học dần, nó giúp class tường minh hơn tuy nhìn class khá khó chịu và dù gì các bạn cũng phải dùng scss, sass... sau này thôi, không tránh được. Sẽ có 1 số quan niệm riêng khi mỗi người học về BEM như vấn đề số 2 "btn btn--small" và "btn--small", tuy nhiên không có đúng hay sai, quan trọng nhất là thống nhất team làm như thế nào để dễ phát triển và edit khi cần. Trên đây là những ý kiến của mình về BEM, mọi người cứ thoải mái chém vì mình cũng chỉ là gà mờ thôi, rất mong các cao nhân vào chỉ giáo thêm

Highlight: BEM là viết tắt của Block Element Modifiers – một quy tắc giúp bạn đặt tên các selector của CSS.

Chào các bạn,

Bạn có bao giờ code CSS mà không biết phải đặt tên class như thế nào không? Mình thì có đấy. Nhất là khi maintain dự án, mất bao nhiêu công mới nghĩ ra được cái tên hay thì lại bị người người trước dùng mất rồi. Tự nghĩ Code CSS thì nên tập trung vào việc căn chỉnh các thuộc tính, chứ không nên mất nhiều thời gian vào cách đặt tên, nên mình đã đi tìm hiểu xem có cái quy tắc nào trong cách đặt tên không, để rồi cứ theo quy tắc là làm, đỡ phải nghĩ nhiều.

Sau một hồi lục sục trên mạng, mình thấy có cái quy tắc BEM này khá hay nên viết bài để chia sẻ tới mọi người.

I. Quy tắc BEM là gì?

BEM là viết tắt của Block Element Modifiers – một quy tắc giúp bạn đặt tên các selector của CSS.

Block Element Modifiers nghĩa là “Khối – Phần tử – Biến thể”, dịch ra Tiếng Việt nghe không được sát nghĩa và có vẻ không “chuyên nghiệp”, nên thôi mình cứ để Tiếng Anh nhé.

Với quy tắc BEM, nó sẽ chia các class css ra làm 3 loại:

  • class định nghĩa cho một block
  • class định nghĩa cho các element trong block
  • class định nghĩa các “biến thể” cho block hoặc cho element trong block.

Rắc rối nhỉ, thôi thì xem cái ví dụ này để dễ hiểu hơn bạn nhé.

CSS viết theo quy tắc BEM

/* class định nghĩa một block */ .product { } /* class định nghĩa element của block */ .product__title { } .product__description { } .product__image { } /* class định nghĩa các "biến thể" của block */ .product--style-1 { } .product--big { } .product--small { } .product__title--style-1 { }

HTML sử dụng CSS viết theo quy tắc BEM

Iphone 11 Pro
Siêu đắt

Từ hai đoạn code trên bạn có thể thấy:

  • product là một block, style của nó được định nghĩa thông qua class .product
  • .product__title, .product__image, .product__description lần lượt là các class element.
  • .product--style-1, .product--big, .product--small, .product__title--style-1 là các class “biến thể”.

Tổng quát lại, chúng ta có thể thấy một class viết theo quy tắc BEM sẽ có cấu trúc như sau

Block__Element--Modifier

Với cách đặt tên kiểu này, các css selector sẽ khó mà trùng nhau được.

II. Lợi ích khi sử dụng BEM

Lợi ích mà ai cũng thấy được ngay đó là BEM giúp chúng ta giảm khả năng 2 css selector bị trùng nhau – giống như ngay từ đầu mình đề cập. Nhưng ngoài ra, BEM còn có một số lợi ích khác:

  • Giúp bạn hình dung ra được cấu trúc của một block HTML sẽ sử dụng các class này.
  • Dễ dàng nắm bắt được các thành phần phụ thuộc lẫn nhau.
  • Với BEM, nó làm “phẳng” các class, không có sự lồng cấp kiểu .a .b .c, giúp bạn không cần phải để ý tới độ ưu tiên [specificity] khi code css.
  • Giảm công sức của developer trong việc phải cố nghĩ ra một cái tên vừa hay vừa chưa tồn tại.

Ngoài các lợi ích kể trên, BEM còn phù hợp để triển khai với SCSS

Ví dụ: Vẫn là đoạn CSS ở ví dụ trên, nhưng giờ mình viết theo SCSS.

.product { &__title { &--style-1 { } } &__description { } &__image { } &--style-1 { } &--big { } &--small { } }

III. Một số ý kiến không đồng tình với quy tắc BEM

Dù có nhiều lợi ích, nhưng có nhiều người không thích dùng quy tắc này vì

Nó dài và xấu

Mình công nhận điều này, nếu không cận thận bạn sẽ có .Mot-cai-class__dai--ngoang-ngoang-the-nay.

Nhưng dài mà mang đủ ý nghĩa, đảm bảo không bị trùng thì cũng không sao. Còn xấu thì… nhìn nhiều khắc quen.

Nó có vẻ không cần thiết

Quay trở lại với ví dụ ở phần đầu, mình có thể viết CSS không tuân theo quy tắc BEM và vẫn đáp ứng được một số lợi ích của BEM như sau:

.product { } .product .title { } .product .description { } .product .image { } .product.style-1 { } .product.big { } .product.small { } .product .title.style-1 { }

Nhìn còn có vẻ gọn ngàng hơn đấy chứ, nhưng khi dự án phát triển tới một “cảnh giới” nhất định thì liệu bạn có chắc chắn các class sẽ không bị đặt tên chồng chéo không? Giả sử ở đâu đó trong project đã có ai đó định nghĩa các class .title, .image, .description rồi thì sao?

// Ai đó đã định nghĩa trước các selector thế này .title { } .description { } .image { }

Không biết bạn có cảm thấy không hài lòng với BEM ở chỗ nào không?

IV. Tổng kết

Tổng kết lại thì:

  • BEM là quy tắc đặt tên class cho CSS, mang lại nhiều lợi ích nhưng quan trọng vẫn là giúp developer bớt phải nghĩ ra cái tên vừa hay vừa chưa được sử dụng.
  • BEM sẽ tuyệt vời hơn khi sử dụng với SCSS
  • Có nhiều người không thích BEM vì nó làm tên class dài và xấu, hoặc họ tự có phương pháp khác thay thế BEM.

Còn bạn thế nào, bạn có thấy BEM cần thiết trong dự án của mình không? Hãy để lại comment cho mình biết với.

Video liên quan

Chủ Đề