CSS3 Dropdown Navigation

ตัวอย่างการเขียน เมนูแบบ dropdown

เมื่อก่อนหรือแม้แต่ตอนนี้หลายคนที่เข้ามาอ่านบทความคงแปลกใจว่า ทำไมผมเขียนบทความที่เกี่ยวกับเรื่อง Selectors ของ CSS ทั้งนั้น สาเหตุหลักๆ ก็เพราะว่า Property และ Value ของ CSS นั้นมันตายตัวครับ จำง่าย ทำบ่อยๆ ก็จำได้ มันไม่เปลี่ยนไปไหนนอกจาก W3C ได้เปลี่ยนเวอร์ชั่นของ CSS ใหม่ เพิ่มหรือลดลง แต่ถ้าเป็น Selectors แล้วนั้น เราไม่ค่อยได้เขียนซ้ำกันสักเท่าไหร่ในแต่ละงาน เพราะงานแต่ละชิ้นที่ทำนั้นมันมีความต่างในตัวของมันเอง เราจึงไม่สามารถใช้ Selector เดิมๆ ในการจัดการได้ แต่ ทั้ง properties และ values นั้น มันเหมือนเดิม

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

ในบทความนี้ก็เช่นกัน ทุกท่านจะเห็นว่าผมเขียน Selectors ของ CSS แปลกๆ มีแค่ Heading Level (X) เท่านั้นที่ถูกร้องขอให้มี Class

ยังเหมือนเดิม Class ของ HTML ไม่ได้มีไว้เพื่อให้เขียนคำสั่งของ CSS เข้าไป แต่เป็นการอนุโลมให้ใช้ได้ เพราะ Class เป็น Global Attribute เหมือนการเป็นของสาธารณะ ภาษาอื่นใดอยากมาใช้ก็เอาไปใช้ ไม่ว่ากัน

เพราะฉะนั้น การลด ขยะ Classes จึงถือเป็นความจำเป็นและเป็นหนึ่งในนโยบาย ประชาวิวัฒน์ ในยุค พ.ศ. 2554 ของเรา

ภาษา CSS มีความสามารถมากมายมาให้ใช้แล้ว ก็จงใช้ อย่าไปขยันน้อย ดันทุรังใช้แต่ Class และ ID Selectors ในการทำงาน

หากันเยอะแยะซะเหลือเกิน เรื่องของการเขียน เมนูแบบ Dropdown สงสัย CSS Designer ทุกวันนี้ เขียนแต่เมนูขายกัน

เอาก็เอา เผื่อกลการค้นหามันจะนำพา Seekers ทั้งหลายไปสู่อะไรสักอย่างได้ แต่ก็ใช่ว่าจะกินกันง่ายๆ เช่นเคย ด้วยความเกรียนแตก สก้อยซ์ เข้าแทรก ผมดันเขียน ตัวอย่างด้วย CSS3 แต่ภาษาโครงสร้างนั้น ใช้ XHTML

ตัวอย่าง การเขียน CSS Dropdown Navigation

ให้เปิดตัวอย่างแล้วก็ดูตามไปด้วยนะครับ

รายละเอียดคร่าวๆ ที่ต้องอธิบาย

  1. สีพื้นหลังของ แทก a ผมไม่ได้ใช้ การ gradient ของ CSS เพราะ webkit กับ Mozilla ยังตกลงกันไม่ได้ว่าจะเขียนแบบไหน ผมเลยใช้ box-shadow แบบ inset แทน
  2. ในตัวอย่าง ผมเขียน Selectors แยกชุดกันออกไป อาจจะมี Selector ที่ซ้ำกัน นั่นก็เพราะว่า
  3. การเขียน Selector แยกออกจากกัน ช่วยในการจัดการ Property ของ CSS ได้ดีขึ้น เช่น
  4. ถ้าใครแอบเอา ตัวอย่างนี้ไปใช้ ก็จะได้หาที่เปลี่ยนสีได้ง่าย เพราะผมเอาเรื่อง สี ไปกองไว้ที่เดียวกัน หรือแก้เรื่อง transition ใหม่ได้ง่าย และที่สำคัญ
  5. การเขียนแยกหมวดหมู่อย่างที่เห็นนั้น มันทำให้การจัดการโครงสร้างหลักในเว็บใหญ่ๆ ได้ดียิ่งขึ้น
  6. ผมใช้การสั่งงานผ่าน Adjacent Sibling (h2+ul) เพราะตามกฎของการเข้าถึงแล้ว list ใดๆ ควรมี headeing level นำหน้าเสมอ เพราะฉะนั้นเพื่อเป็นการดักการมองข้ามเรื่องนี้ไป จึงต้องสั้งแบบ header+ul ถ้าใครไม่อยากให้ header โผล่ออกม่ ก็ เอามันไปซ่อน

ลองมาไล่ดูกันครับ

Flaot, Clear และ Position

/*Clear float*/
[class*="-เมนูหลัก"]+ul::after {
 content: ' ';
 display: block;
 clear: both;
}
/*Float*/
[class*="-เมนูหลัก"]+ul>li {
 float: left;
}
/*Position*/
[class*="-เมนูหลัก"]+ul>li, [class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li {
 position: relative;
}
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>ul {
 position: absolute;
}

เมื่อมี Float ก็ต้องมี Clear การเขียน Dropdown เมนูนั้น สิ่งที่จะต้อง float มันอันเดียวคือ li นอกสุด เสร็จแล้วก็ Clear ด้วยเทคนิคการ ส้รางเนื้อหาเปล่ามาหลอก และสั่ง position เป็น Relative เพื่อที่จะให้ลูกหลานของมันเองนั้นอ้างอิงค่าตำแหน่งจากมัน นั่นก็คือ ul ที่เป็น ลูกและหลานของมันเอง ที่ตำแหน่งเป็น absolute

Width หรือความกว้างของแต่ละ ช่องลิงค์

[class*="เมนู-แนวนอน"][class*="สี่"]+ul>li { width: 25%;}
[class*="เมนู-แนวนอน"][class*="ห้า"]+ul>li { width: 20%;}
[class*="เมนู-แนวนอน"][class*="หก"]+ul>li:not(:last-child) { width: 16.5%;}
[class*="เมนู-แนวนอน"][class*="หก"]+ul>li:last-child { width: 17.5%;}

สังเกตว่า ผมจะใส่คำว่า สี่ ห้า หรือ หก เข้าไป จาก Selectors ด้านบนนั้น ให้นับจำนวน เมนูก่อนว่ามันมีกี่อัน แล้วเอาไปหารด้วย 100 ค่าที่ได้ค่อยเอามาเป็นค่าความกว้างของ li ที่ถูกสั่ง float: left ไปก่อนหน้านี้

แต่พอ ผมมี li 6 อัน มันหารไม่ลงตัว ผมจึงเลือกใช้วิชามาร สั่ง li 5 ตัวแรกกว้าง 16.5% ก่อน แล้วความสั่งตัวที่ 6 กว้างกว่าชาวบ้าน

ในการเอาไปใช้งานจริง ถ้าหน้าเว็บเราเป็น Pixel Base เราจะรู้อยู่แล้วว่ามันมีพื้นที่เหลือให้ เมนู แสดงผลอยู่เท่าไหร่ ค่อยเอาเอาไปหาร แล้วสามารถสั่ง li ให้กว้างเป็น px จะได้ ฟิต สตาร์ทติดง่าย ไม่ต้องพึ่งพาไดเกียว

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

ใช่สิ เรากำลังทำเมนูอยู่ มีเมนู ก็ต้องสั่ง …. ตึกโป๊ะ อยู่ในร้านข้าวต้มเลยทีเดียว

การเกิดขึ้นและดับไปของ ul ที่เป็นลูกและหลาน

[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul {
 visibility: hidden;
 opacity: 0;
 width: 0;
 height: 0;
 top: 0px;
}
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul {
 width: 100%;
 top: 35px;
 z-index: 99;
}
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li:hover>*:first-child+ul {
 visibility: visible;
 opacity: 1;
 height: auto;
}
[class*="เมนู"][class*="_สองชั้น"][class*="หก"]+ul>li>*:nth-child(1)+ul>li:hover>*:first-child+ul {
 width: 100%;
 left: 100%;
 z-index: 100;
}

ผมไม่ได้ใช้ Display ในการการสั่งว่า แสดงเป็น xxx หรือแสดงเป็น ว่างเปล่า เพราะผมรู้สึกว่า การสั่งว่า แสดงเป็น xxx หรือแสดงเป็น ว่างเปล่านั้นมันใช้คำสั่งไม่ถูกต้อง เพราะเมนูที่ต้อง dropdown มันมีอยู่ แค่เราต้องการให้มองเห็น หรือ ไม่ให้เห็นเท่านั้น

เมื่อคิดพบดังนั้น ผมก็ไปมองหา property ที่สั่งว่า มองเห็น หรือ มองไม่เห็น ใช่ครับ มันคือ visibility สั่งให้มัน hidden หรือ Visible เอาตามสะดวก

คำสั่งที่สำคัญต่อไปคือ คำสั่ง top ของ ul ที่เป็นลูก และคำสั่ง left ของ ul ที่เป็นหลาน แล้ว top: 35px มาจากไหน มาจาก a ที่ถูกสั่ง line-height เป็น 35px (ดูข้างล่าง) โดยที่ width กับ left นั้น ค่าที่ได้ มาจากการ สืบทอด

คำสั่งอื่นๆ ที่เหลือ เป็นเพียงแค่น้ำจิ๋ม เอามาทำ Effect การแสดงผลในขั้นตอนการ Transition เท่านั้นครับ

ลูกตัวแรกของ li


[class*="-เมนูหลัก"]+ul>li>*:nth-child(1), 
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>*:first-child, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 display: block;
}

ทำไมผมไม่สั่ง เป็น [class*=”-เมนูหลัก”] li a { display: block;} ก็เพราะว่า บางการใช้งาน ตัวแรก มันไม่ใช่ a มันอาจจะเป็น span,strong, em หรือ อื่นๆ การที่ใช้ *:first-child หรือ *:nth-child(1) ช่วยให้เมื่อเราเปลี่ยนจาก เธอ ไปเป็นอื่น ทำให้ชีวิตเรายังอยู่ได้ ไม่ทรมานมาก เพราะยังไงเปลี่ยนไปแล้วยังเป็น ที่หนึ่ง อยู่นั่นเอง

โอย … มันยาว กุเหนื่อย วันที่ 4 แล้วเนี่ย กับเรื่องนี้ บ่น แต่ก็เขียน

Font และรูปแบบการเกิดของ ตัวหนังสือ

[class*="-เมนูหลัก"][class*="สี่"]+ul>li>*:nth-child(1) {
 font-family: Georgia, "Times New Roman", Times, serif;
}
[class*="-เมนูหลัก"][class*="ห้า"]+ul>li>*:nth-child(1), 
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>* {
 font-family: Lobster;
}
[class*="-เมนูหลัก"][class*="หก"]+ul>li>*:nth-child(1) {
font-family: Kilogram;
}
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>* {
 font-size: 1.2em;
}
[class*="-เมนูหลัก"][class*="ห้า"]+ul>li>*:nth-child(1), [class*="-เมนูหลัก"][class*="หก"]+ul>li>*:nth-child(1) {
 font-size: 1.5em;
}
/*Styling font*/
[class*="-เมนูหลัก"]+ul>li>*:nth-child(1), 
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>a, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 line-height: 35px;
 font-weight: 400;
 text-transform: uppercase;
 letter-spacing: 1px;
}

อธิบาย ไม่มาก เพราะมันเป็นเรื่องเก่า แค่การจัดการตัวหนังสือ แต่ มันอาจจะต่างมาหน่อยในเรื่อง font-family: Kilogram; และ font-family: Lobster; ซึ่งทั้งสองอันนี้ เกิดจากการ เพิ่ม font-face เข้ามา

line-height ส่วนสำคัญที่ทำให้เมนูแต่ละอันมีความสูงเท่ากัน ข้อควรสังเกต การสั่งงานอะไรก็ตามที่คิดว่ามันจะมีแถวเดียว ให้สั่ง ความสูงของแถวแทน height หรือ การอัด padding top หรือ bottom เข้าไป เพราะมันอาจจะทำให้เราสับสนกับสัดส่วนที่เกิดขึ้น

พื้นหลัง เส้นขอบ และ สี

[class*="-เมนูหลัก"]+ul>li>*:nth-child(1), 
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>a, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 color: rgba(50, 50, 50, .7);
}
[class*="-เมนูหลัก"]+ul>li:hover>*:nth-child(1), 
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li:hover>*:first-child, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li:hover>*:first-child {
 color: rgba(50, 50, 50, 1);
}
[class*="-เมนูหลัก"]+ul>li>*:nth-child(1), [class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>a, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 text-shadow: 1px 1px 0px rgba(255, 255, 255, .9);
 box-shadow: 0px -15px 25px 0px rgba(50, 50, 50, .3) inset;
}
[class*="-เมนูหลัก"]+ul>li:hover>*:nth-child(1), 
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li:hover>*:first-child, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li:hover>*:first-child {
 box-shadow: 0px 25px 25px 0px rgba(50, 50, 50, .4) inset;
}
[class*="-เมนูหลัก"]+ul {
 border: solid 1px rgba(50, 50, 50, .15);
}
 [class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li>*:first-child, 
 [class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 border-left: solid 4px rgba(50, 50, 50, .3);
}
[class*="เมนู-แนวนอน"]+ul>li:not(:first-child)>*:first-child {
 border-left: solid 1px rgba(255, 255, 255, .3);
}
[class*="เมนู-แนวนอน"]+ul>li:not(:last-child)>*:first-child {
 border-right: solid 1px rgba(50, 50, 50, .35);
}
[class*="เมนู"][class*="_สองชั้น"]+ul>li:hover>*:nth-child(1)+ul>li:hover>*:first-child, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li:hover>*:first-child {
 border-left: solid 4px rgba(50, 50, 50, .6);
}
 [class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child, 
 [class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 border-top: solid 1px rgba(255, 255, 255, .3);
}
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child, 
[class*="เมนู"][class*="_สองชั้น"]+ul>li>*:nth-child(1)+ul>li>*:first-child+ul>li>*:first-child {
 border-bottom: solid 1px rgba(50, 50, 50, .35);
}

สีที่ผมใช้เป็น rgba() ถ้าต้องการแก้ไข ก็สามารถแก้ไขได้ง่ายๆ ในโซนนี้ แค่นั้นเอง

ตัวอย่าง การเขียน CSS Dropdown Navigation

อธิบายประมาณนี้น่าจะสามารถเอาไปต่อกันได้นะครับ

มีความสุขกับการใช้ชีวิตครับ

หมายเหตุไทซีเอสเอส

การเขียน Dropdown Navigation หรือ CSS Dropdown menu ชุดนี้เป็นหนึ่งใน Module ของ ThaiCSS : CSS3 HTML5 Web Layout Framework ที่ผมกำลังพัฒนาอยู่ ใช่ครับ ผมกำลังพัฒนา Framework ในส่วนของการใช้ CSS กับ HTML เพื่อจัดการหน้าเว็บ แต่ว่า จะมีสักกี่คนที่กล้าเอาไปใช้งาน เอิ้ก… ต้องรอดูกันต่อไป และที่สำคัญ ผมยังไม่รู้ว่ามันจะเสร็จเมื่อไหร่ เพราะการเขียน คู่มือการใช้งาน คือส่วนที่ถือว่ายากที่สุดในการทำ อะไรสักอย่าง ที่ต้องการให้คนอื่นสามารถเอาไปใช้งานต่อได้อย่าง ง่าย และถูกต้องตามวัตถุประสงค์ อย่างเช่น CSS HTML Framework ที่ผมกำลังทำอยู่นี้

Back to Top

6 Responses to CSS3 Dropdown Navigation

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to Top