ทุกท่านเคยปัญสบปัญหาเหล่านี้หรือไม่ ไม่ว่าจะเป็นการมึนงงว่าจะเขียน 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/
ทั้งนี้ผมไม่ได้คาดหวังว่าทุกคนจะเข้าใจในทุกๆส่วนแต่ผม อยากให้หลังจากที่ทุกๆคนอ่านแล้ว ไปลองลงมือทำเพื่อพัฒนาความรู้ความเข้าใจ กันนะงับ