การเขียน CSS ในรูปแบบของ BEM

ทุกท่านเคยปัญสบปัญหาเหล่านี้หรือไม่ ไม่ว่าจะเป็นการมึนงงว่าจะเขียน class ยังไง ปัญหาเหล่านี้จะหมดไป เพียงแค่ทุกท่านไม่ต้องเขียน แล้วปิดไฟเข้านอนซะ

เดี๋ยวๆ ล้อเล่นนะครับอย่าเพิ่งโกรธกัน โดยวันนี้นะครับ เราจะมาแก้ปัญหาปัญหาในส่วนตรงนี้กันครับโดยเทคนิคที่ผมจะนำมาแชร์ในบทความนี้เป็นการเขียน CSS รูปแบบ BEM นะครับ มาเริ่มกันเลย

BEM

ย่อมาจาก Block Element Modifier โดยที่แต่ละตัวอธิบายได้ดังนี้

Block
อยู่ได้เดี่ยวๆและมีความหมายในตัว
เช่น header, footer, container, card

Element
ต้องอยู่ภายใน block ถึงจะมีความหมายตรงตัว
เช่น menu item, list item, header title

Modifier
ลักษณะ หรือ คุณสมบัติของ Element หรือ Block
เช่น header nav pink, button small, shape square red

หลักการการตั้งชื่อแบบ BEM

จริงๆแล้วการตั้งชื่อของ BEM หลายแบบอยู่นะแต่ขอยกตัวอย่างแบบ คลาสสิคมาละกัน
หรือเราเรียกกันว่า Two Drash Style

#ทั่วไปแบบไม่มี modifier
block__element

<div class="card">
<header class="card__title">...</header>
<figure class="card__figure">
<img class="card__img"/>
</figure>
<p class="card__paragraph">...</p>
</div>

#ทั่วไปแบบมี modifier
block__elemen–modifier_name_value

<div class="card card--profile">
   <header class="card__title card__title--big">...</header>
   <figure class="card__figure card__figure--small">
      <img class="card__img card__img--square"/>
   </figure>
   <p class="card__paragraph">...</p>
</div>

#กรณีชื่อยาว
ใช้- เพื่อแบ่งข้อความให้อ่านง่าย
block-name__element-name_name_value

<div class="register-form">
   <input type="text" class="register-form__input">
   <input type="text" class="register-form__input">
   <div class="register-form__button">
<div>

รูปแบบของ BEM

ใน class จำเป็นต้องมีรูปแบบ block__element ดังนั้นหมายความว่าไม่ควรมี element ต่อท้าย block เกินหนึ่งตัวแบบนี้ block__element__element__.. .. .. เพราะเราไม่ได้ต้องการต่อกันเป็นทอดๆ เราต้องการให้อย่างน้อย element นั้นๆต้องมีการบอกว่ามันอยู่ใน block ไหนสัก block หนึ่ง

สิ่งที่บางคนเคยเข้าใจผิดๆ

สำหรับคนที่อาจเคยศึกษาเองมาบ้างแล้วอาจจะเข้าใจว่าจะต้องเขียน element ตัวเองต่อจาก element ที่ซ้อนมา อีกที งงไหม ? มาดูตัวอย่างกัน

<header class="header">
   <nav class="haeder__nav>
      <div class="header__nav__item">
         <a class="header__nav__item__link header__nav__item__link--a">A</a>
      </div> 
      <div class="header__nav__item">
         <a class="header__nav__item__link header__nav__item__link--b">B</a>
      </div> 
      <div class="header__nav__item">
         <a class="header__nav__item__link header__nav__item__link--c">C</a>
      </div>
   </nav>
</header>

แบบข้างต้นดูจะเหมือนปกติแต่ก็ไม่นะครับอย่าลืมนะเราไม่เจำเป็นต้องซ้อนกันเยอะแยะครับ วิธีแก้ก็ง่ายๆเพียงให้แต่ละบรรทัด มันชี้ไปยัง block ตัวแรกของมันพอ ถ้างงมาดูอันที่แก้ให้ตรงตาม รูปแบบของ BEM ให้แล้วครับ

<header class="header"> ~ block / base
   <nav class="header__nav>
      <div class="header__item">
         <a class="header__link header__link--a">A</a> 
      </div> 
      <div class="header__item">
         <a class="header__link header__link--b">B</a>
      </div> 
      <div class="header__item">
         <a class="header__link header__link--c">C</a>
      </div>
   </nav>
</header>

เป็นไงบ้างครับ การเขียนแบบนี้ สังเกตุได้เลยแต่ละบรรทัดจะเป็นในรูปแบบ block__element เช่น header__link มี header เป็น block และ link เป็น element 🙂

จุดอ่อนของ BEM

หลังจากที่เขียนคุณอาจจะนึกขึ้นมาในหัวว่า ขุ่นพระ !!!ถ้าเขียนแบบ BEM ทำให้ต้องมี class เยอะแยะไปหมดใช่ไหม คำตอบคือ ถูกต้องครับ class เยอะ แต่เอาจริงๆก็ไม่ใช่เรื่องที่น่าหนักใจหรอกนะ คริๆ

ประโยชน์ของ BEM

Modularity
ในการตกแต่งแต่ละบล็อคนั้น ในแต่ละบล็อคจะขึ้นอยู่กับตัวมันเองเสมอ ดังนี้ทำให้เราย้ายบล็อคไปมาได้โดยไม่กระทบ พื้นที่อื่นๆ

Reusability
ตามหลัก โมดูล เราสามารถนำมันไปใช้ต่อในส่วนตรงอื่นๆได้ เพื่อลดการเขียน css

Structure
การเขียนแบบ BEM นั้นจะทำให้ css code ดูมีโครงสรา้งที่มีระเบียบมากๆ และทำให้อ่านง่ายเข้าใจได้ง่าย

CSS Selector หละ จะเรียกใช้ยังไง

มีรูปแบบดังนี้
block
block__element
block__element — modifier

------------------------------HTML----------------------------------
card
   card__wrapper
   card__figure
      card__img card__img--square
   card__text------------------------------CSS-----------------------------------
.card {...}
.card__wrapper {...}
.card__figure {...}
.card__img {...}
.card__img--square {...}
.card__text {...}

ข้อควรระแวงของ BEM

#ระวังเรื่องการใช้ idในการตกแต่งแทน class
เพราะ idควรไว้ใช้กับสิ่งที่สำคัญมากๆและไม่ซ้ำใคร จริงๆเช่นเอาไว้ใช้เกี่ยวกับ Javascript ไม่ก็ Input Checkboxต่างๆ

#ระวังเรื่องการใช้ selector ซ้อน element
ถ้าใช้เมื่อไรปุ้บหลุดคอนเซ็ปของ BEM ในเรื่องของการปรับเปลี่ยนแก้ไขได้ง่ายเลย
เพราะอย่าลืมแต่ละตัวมันก็มี style ของมันเอง

อันนี้ยกตัวอย่างเรื่อง selector ซ้อนกันนะ

.Block .ฺBlock__Element_1 .Block__Element_2 {...} 

ถ้าทำแบบข้างต้น เมื่อวันใดวันหนึ่งเกิดเราเอา .BLock__Element_1 ออกไป .Block__Element_2 ก็จะโดนปัญหาไปอีก เพราะฉนั้น BEM จึงอยากให้แยกไว้แต่ละตัวแบบนี้

.Block
.Element_1
.Element_2

Block สามารถ ซ้อนกันได้ด้วยนะ

<div class="register">
   <div class="register__form">
      <div class="register__section register__section--general">
         <input  type="text"   class="register__input"><input>
         <button type="submit" class="register__button"></button>  
     </div>
     <div class=""register__section register__Section--gender>
         <input type="checkbox" class="register__checkbox"><input>
         <input type="checkbox" class="register__checkbox"><input>
     </div>
   </div>
<div>

จริงๆข้างต้นก็เขียนถูกแล้วแหละแต่ ดูดีๆอะไรๆก็อยู่ใน block register ไปหมด จะดีกว่าไหม หากเราแยก element ของ block มาเป็น อีก block เลยก็ได้ เพราะเวลาบางทีเมื่อเริ่มเขียน css เยอะๆแล้วเดี๋ยวมันจะงงถ้าใช้ base ตัวเดียว ถ้าไม่เข้าใจลองดูแบบข้างล่าง

<div class="register">
   <div class="register__form">
      <div class="general register__section>
         <input  type="text"   class="general__input"><input>
         <button type="submit" class="general__button"></button>  
     </div>
     <div class="gender register__section>
         <input type="checkbox" class="gender__checkbox"><input>
         <input type="checkbox" class="gender__checkbox"><input>
     </div>
   </div>
<div>

ยังคงตรงตามกฏของ bem อยู่นะ เอ้อออ ทั้งนี้นี้หละที่จะอธิบายก็คือ เมื่อใดก็ตามเรารู้สึกว่า element มันมีอะไรแยกย่อยมาเยอะ แนะนำไปให้แยก ไปเป็น อีก blockได้เลย แต่ตอนแยกมันออกมา ควรมีบอกด้วยนะว่าตัวที่แยกมา เคยเป็นอะไร แบบ
general register__section หมายว่า general เป็นส่วนหนึ่งของ register__section
และในตัวอย่างวิเคราะห์ออกมาได้ว่า register เป็น block ใหญ่ที่มี general และ gender เป็น block ลูก

เทคนิค

#เขียนให้สั้นลง อีกนิส

จาก block-name__element-name
เช่น news-story__text-content

เป็น blockName-elementName
เช่น newsStory-textContent

#หากกลัวว่าเกิดการทับกันของ css แต่ละไฟล์
ให้ตั้งชื่อ block ใหญ่สุด ให้ไม่ซ้ำ แล้วซ้อน element ที่ต้องการแสดงไว้ในนั้นเช่น

#HTML
login-page
   login-input
   login-button#CSS
.login-page login-input
.login-page login-button

ทีนี้หน้าอื่นที่มี login-input ก็จะไม่ได้ดึงตัวนี้ไปใช้เพราะหน้าอื่น base block ใหญ่สุดที่คลุม login-input ไม่ใช้ login page //ถึงตรงนี้บางคนอาจจะมองว่าแล้วมันนำมาใช้ใหม่ไม่ได้อะดิ ถ้ามันเป็นแบบนี้ คำตอบคือใช่ การนำมาใช้ใหม่ในที่นี้คือใช้กับ block ใหญ่แค่นั้นเอง คือใช่ใหม่ถายใน block login-page แค่นั้น

#เขียน css selector BEM ให้มันมือด้วย SCSS

ตรงนี้ไม่ลงลึกละกันเอาเป็นว่าไปลองหาอ่านเรื่อง BEM SCSS ดู ผมแนะนำแบบสุดโต่งเลยว่าของโครตดี เขียนเป็นระเบียบและเขียนไม่รก แถมใช้เวลาเข้าใจไม่นานด้วยไอเจ้า SCSS + BEM เนี้ย

กรณีตัวอย่างต่างๆ

สำหรับคนที่ยังมึนๆ ผมจะยกตัวอย่างสั้นๆ 2 มิลลิเมตร มาให้ดูเลยละกัน
ในตัวอย่างจะไม่เขียน Tag HTML นะครับ แต่จะเขียนชื่อ block ไม่ก็ element ไปเลย

#1
card
   card__title
   card__figure
      card__img
      card__content#2
header
  nav header-nav
    nav-item nav-item_left
    nav-item nav-item_right#3
main
   content main-content
      content-side content-side_left
        content-text
      content-side content-side_right
        content-text#4
article
  article-grid
  article-header
  article-img
  article-paragraph#5
product-order
   product-list
       card
          card-header
          card-img
          card-content#6
seachBar
   searchBar-field
   searchBar-figure
     searchBar-img#7
slider
   slider-layout
      frame frame_1 slider-frame
        frame-img
      frame frame_2 slider-frame
        frame-img

สรุป

การที่เราใช้ BEM ผมมองว่ามันค่อนข้างเป็นประโยชน์มากๆเมื่อต้องทำงานกันเป็นทีมที่ต้องการมีมาตราฐานไว้ใช้ร่วมกัน อย่างไรก็ตามในบางส่วน เราอาจไม่จำเป็นต้อง ทำตามกฏตรงๆ ก็ได้ เน้นเลยนะ ไม่ต้องทำตรงตามกฏมากก็ได้ แต่ให้เราลองหาวิธีการที่ทำแล้วสบายใจและปรับปรุงแก้ไขเข้าใจได้ง่ายก็พอ ทั้งนี้การมีมาตราฐานที่วางมาให้ไว้แล้วก็ทำให้เรามี ฐานความคิดที่จะนำไปปรับปรุงต่อยอดได้ดียิ่งขึ้น สำหรับในเรื่องของ BEM ยังมีอะไรให้อ่านอีกเยอะ ว่างๆก็ลองไปอ่านจะ Document BEM https://en.bem.info/methodology/quick-start/

ทั้งนี้ผมไม่ได้คาดหวังว่าทุกคนจะเข้าใจในทุกๆส่วนแต่ผม อยากให้หลังจากที่ทุกๆคนอ่านแล้ว ไปลองลงมือทำเพื่อพัฒนาความรู้ความเข้าใจ กันนะงับ

ขอบคุณข้อมูลจาก
https://medium.com/@danusoncheounsanguan/css-%E0%B9%83%E0%B8%99%E0%B8%A3%E0%B8%B9%E0%B8%9B%E0%B9%81%E0%B8%9A%E0%B8%9A%E0%B8%82%E0%B8%AD%E0%B8%87-bem-f2ab1a09f533

Write a comment