องค์ประกอบ HTML สองรายการที่มีแอตทริบิวต์ id เดียวกัน: มันแย่ขนาดไหน?


122

เพียงแค่เรียกดูซอร์สโค้ดของ google maps ในส่วนหัวของพวกเขาพวกเขามี 2 divs ที่มี id = "ค้นหา" หนึ่งประกอบด้วยอื่น ๆ และยังมีแอตทริบิวต์ jstrack = "1" มีรูปแบบแยกพวกเขาเช่นนั้น:

<div id="search" jstrack="1">
    <form action="/maps" id="...rest isn't important">
        ...
        <div id="search">...

เนื่องจากนี่คือ google ฉันคิดว่ามันไม่ใช่ความผิดพลาด

ดังนั้นมันจะเลวร้ายจริงๆที่จะละเมิดกฎนี้? ตราบใดที่คุณระมัดระวังในการเลือก css และ dom ทำไมไม่ลองใช้คลาสเหมือน id ไม่มีใครทำสิ่งนี้โดยเจตนาและถ้าเป็นเช่นนั้นทำไม?


102
"เนื่องจากนี่คือ google ฉันคิดว่ามันไม่ใช่ความผิดพลาด" -> Google ไม่ผิดพลาด พวกเขาทำผิดพลาดเหมือนกับพวกเราที่เหลือ
Joeri Sebrechts

43
อันที่จริงแล้วคนที่ google ได้ค้นหาการยึดติดอยู่ในใจของพวกเขาดังนั้นพวกเขาจึงไม่สามารถนึกถึง id อื่น ๆ ได้: P
Pankaj Upadhyay

10
ฉันรู้สึกว่าหน้านั้นมีการแสดงผลจากส่วน html ที่แตกต่างกันดังนั้นผู้พัฒนารายหนึ่งในชิ้นส่วนหนึ่งจึงใช้รหัสดังกล่าวและเกิดขึ้นกับผู้พัฒนารายอื่นในส่วนอื่น ๆ
Luciano

10
คำถามทั้งหมดของ "มันช่างเลวจริง ๆ " แค่เตือนฉันเกี่ยวกับเรื่องนี้: xkcd.com/292
Daniel Roseman

3
@DanielRoseman xkcd ก็ทำได้เช่นกัน: what-if.xkcd.com/23/#question
SQB

คำตอบ:


140

สเปคบอกว่า UNIQUE

ข้อกำหนด HTML 4.01กล่าวว่า ID ต้องไม่ซ้ำกันทั้งเอกสาร

ข้อกำหนด HTML 5บอกว่าสิ่งเดียวกัน แต่ในคำอื่น ๆ มันบอกว่า ID ต้องไม่ซ้ำกันในของทรีย่อยบ้านที่เป็นพื้นเอกสารถ้าเราอ่านความหมายของมัน

หลีกเลี่ยงการทำซ้ำ

แต่เนื่องจากตัวเรนเดอร์ HTML นั้นให้อภัยเมื่อมาถึงการเรนเดอร์ HTML พวกเขาจึงอนุญาตให้ใช้รหัสซ้ำกันได้ สิ่งนี้ควรหลีกเลี่ยงหากเป็นไปได้และหลีกเลี่ยงอย่างเคร่งครัดเมื่อเข้าถึงองค์ประกอบโดยทางโปรแกรมด้วยรหัสใน JavaScript ฉันไม่แน่ใจว่าgetElementByIdฟังก์ชันใดควรส่งคืนเมื่อพบองค์ประกอบที่ตรงกันหลายรายการ ควรเป็น:

  • ส่งคืนข้อผิดพลาดหรือไม่?
  • คืนองค์ประกอบที่ตรงกันก่อนหรือไม่
  • คืนองค์ประกอบที่ตรงกันล่าสุดหรือไม่
  • คืนชุดองค์ประกอบที่ตรงกันหรือไม่
  • ไม่มีอะไรคืน?

แต่แม้ว่าเบราว์เซอร์จะทำงานได้อย่างน่าเชื่อถือในทุกวันนี้ไม่มีใครสามารถรับประกันพฤติกรรมนี้ได้ในอนาคตเนื่องจากขัดต่อข้อกำหนด นั่นเป็นเหตุผลที่ฉันไม่แนะนำให้คุณทำซ้ำ IDภายในเอกสารเดียวกัน


1
@missingno: ฉันเพิ่มลิงก์ไปยังข้อกำหนด HTML 5 ที่พูดถึงสิ่งเดียวกัน แต่ใช้ถ้อยคำที่แตกต่างกัน
Robert Koritnik

6
ตามข้อมูลจำเพาะของ DOM "หากองค์ประกอบมากกว่าหนึ่งรายการมีแอตทริบิวต์ ID ที่มีค่านั้นสิ่งที่ส่งคืนจะไม่ได้กำหนด" (ซึ่งหมายความว่าไม่มีผลลัพธ์ "ถูกต้อง" ที่ถูกกำหนดมากกว่าค่าจริงundefined) เป็นความคิดที่ดีที่จะพึ่งพาพฤติกรรมที่ไม่ได้กำหนด
lonesomeday

1
น่าสังเกตเกี่ยวกับ HTML5 data-คุณลักษณะนี้มีประโยชน์สำหรับเมื่อบางคนอาจถูกล่อลวงให้กำหนด ID เดียวกันหลาย ๆ อย่าง สิ่งนี้ช่วยให้คุณมี ID ที่แตกต่างกันมากมายพร้อมกับdata-somethingคุณสมบัติทั่วไปที่เหมือนกัน ยังเบราว์เซอร์ทั้งหมดที่ฉันรู้จักละเว้นคุณลักษณะที่ไม่รู้จักดังนั้นพวกเขาอาจจะปลอดภัยในเบราว์เซอร์ที่ทันสมัยทุกรุ่นที่ขาดการรองรับ HTML เต็มรูปแบบ
Tim Post

2
@JoachimSauer: เมื่อคุณใช้คุณลักษณะข้อมูลคุณสามารถมีคู่ค่าคีย์ซึ่งไม่เป็นจริงเมื่อคุณใช้คลาส CSS ในกรณีนี้พวกเขาทุกคนชอบคุณสมบัติบูลีน องค์ประกอบอาจมีคลาส CSS หรือไม่ หากคุณต้องการค่าที่มีคลาส CSS คุณจะต้องรวมค่าเหล่านั้นเป็นชื่อคลาส CSS และแยกวิเคราะห์ในภายหลัง ฉันหวังว่าคุณจะเห็นประโยชน์ของการใช้dataคุณสมบัติต่างๆ และพวกเขากำลังได้รับการสนับสนุนโดยตรงจากกล่องโดย jQuery เมื่อคุณเพียงแค่อ้างถึงแอตทริบิวต์กับdata-something="123" $(elem).data("something")
Robert Koritnik

1
@RobertKoritnik: แน่นอน! ฉันไม่ได้คิดถึงกรณีใช้งาน id="search"ฉันคิดเกี่ยวกับกรณีของ
Joachim Sauer

30

คุณถามว่า "แย่แค่ไหน" ดังนั้นเมื่อต้องการหาคำตอบ @ RobertKoritnik (ถูกต้องทั้งหมด) สักหน่อย ...

รหัสนั้นไม่ถูกต้อง ไม่ถูกต้องไม่ได้มาในเฉดสีเทา รหัสนี้ละเมิดมาตรฐานและดังนั้นจึงไม่ถูกต้อง มันจะล้มเหลวในการตรวจสอบการตรวจสอบและควร

ที่กล่าวว่าขณะนี้ไม่มีเบราว์เซอร์ในตลาดที่จะบ่นเกี่ยวกับมันหรือมีปัญหาใด ๆ กับมันเลย เบราว์เซอร์จะอยู่ภายใต้สิทธิ์ของพวกเขาในการร้องเรียน แต่ไม่มีเบราว์เซอร์ใดเวอร์ชันปัจจุบันที่ทำอยู่ ซึ่งไม่ได้หมายความว่าเวอร์ชันในอนาคตอาจไม่ปฏิบัติกับรหัสนี้ไม่ดี

พฤติกรรมของคุณพยายามใช้ ID นั้นเป็นตัวเลือกไม่ว่าจะเป็น css หรือ javascript นั้นอาจไม่สามารถเดาได้และอาจแตกต่างกันไปในแต่ละเบราว์เซอร์ ฉันคิดว่าการศึกษาสามารถทำได้เพื่อดูว่าแต่ละเบราว์เซอร์ตอบสนองต่อสิ่งนั้นอย่างไร ฉันคิดว่าในกรณีที่ดีที่สุดมันจะปฏิบัติเหมือน "class =" และเลือกรายการของพวกเขา (นั่นอาจทำให้ไลบรารี JavaScript สับสน - ถ้าฉันเป็นผู้เขียน jQuery ฉันอาจปรับรหัสตัวเลือกให้เหมาะสมเพื่อที่ว่าถ้าคุณมาหาฉันด้วยตัวเลือกที่ขึ้นต้นด้วย "#" ฉันคาดว่าจะมีวัตถุเดียวและรับ รายการอาจทำให้ฉันสมบูรณ์)

นอกจากนี้ยังอาจเลือกอันแรกหรืออาจจะเป็นอันสุดท้ายหรือไม่เลือกเลย ไม่มีทางที่จะบอกได้โดยไม่ต้องลอง

"สิ่งที่เลวร้าย" นั้นขึ้นอยู่กับว่าเบราว์เซอร์ใดที่ใช้ข้อมูลจำเพาะ HTML อย่างเคร่งครัดและต้องทำอย่างไรเมื่อเผชิญหน้ากับการละเมิดข้อกำหนดนั้น

แก้ไข: ฉันเพิ่งเกิดขึ้นเจอในวันนี้ ฉันดึงส่วนประกอบต่าง ๆ จากแบบฟอร์มการค้นหาในเอนทิตีประเภทต่าง ๆ เพื่อสร้างยูทิลิตี้การรายงานแบบ all-in-one ขนาดใหญ่สำหรับไซต์นี้ฉันกำลังโหลดแบบฟอร์มการค้นหาของเพจระยะไกลใน divs ที่ซ่อนอยู่และใส่เข้าไปใน ตัวสร้างรายงานเมื่อเลือกชนิดเอนทิตีที่เหมาะสมเป็นแหล่งที่มาของรายงาน ดังนั้นจึงมีรุ่นที่ซ่อนอยู่ของแบบฟอร์มและรุ่นที่แสดงในตัวสร้างรายงาน JavaScript ที่มาพร้อมกับในทุกกรณีหมายถึงองค์ประกอบตาม ID ซึ่งตอนนี้มีสองบนหน้า - หนึ่งที่ซ่อนอยู่และหนึ่งที่แสดง

สิ่งที่ดูเหมือนว่า jQuery กำลังทำอยู่ก็คือการเลือกฉันเป็นคนแรกซึ่งในทุกกรณีเป็นสิ่งที่ฉันไม่ต้องการ

ฉันกำลังแก้ไขสิ่งนี้โดยการเขียนตัวเลือกเพื่อระบุพื้นที่ของหน้าฉันต้องการรับข้อมูลใน (เช่น: $ ('# containerDiv #specificElement')) แต่มีหนึ่งคำตอบสำหรับคำถามของคุณ - jQuery บน Chrome จะทำงานในลักษณะที่แน่นอนเมื่อเผชิญหน้ากับการละเมิดข้อกำหนดนี้


... คำถามที่เกี่ยวข้อง: stackoverflow.com/q/29295824/287948เกี่ยวกับภาระหน้าที่ของ ID ในโปรไฟล์ด่วน CSS
Peter Krauss

3
"ไม่ถูกต้องไม่ได้มาในเฉดสีเทา" ฉันเห็นสิ่งนี้มากและเป็นหนึ่งในสิ่งที่ถูกต้องทางเทคนิค แต่ไม่ "จริง" ในชีวิตหรือในการเขียนโปรแกรม คุณปกปิดอย่างคลุมเครือในคำตอบของคุณและฉันสามารถอธิบายได้ แต่ฉากนี้จากทฤษฎีบิ๊กแบงทำงานได้ดีมากที่ฉันจะให้มันพูดแทนฉันและหวังว่าจะทำให้ใครบางคนหัวเราะ ... Stuart vs Sheldon youtube.com/ watch? v = F_1zoX5Ax9U
Night Owl

นี่เป็นคำตอบอายุ 8 ปี แต่ฉันคิดว่ามันไม่สมดุลอย่างมากเมื่อคุณถามคำถามของ OP แต่ยังไม่บ่นมากเกี่ยวกับพฤติกรรมที่อนุญาตและเป็นอันตรายของเบราว์เซอร์เกี่ยวกับรหัสซ้ำซึ่งเป็นวิธีที่แย่กว่าสิ่งที่ OP พยายามทำ
erandros

20

มันช่างเลวจริงเหรอ?

  1. มันทำให้ฉันร้องไห้
  2. มันไม่ถูกต้อง
  3. ไลบรารี javascript จำนวนมากจะไม่ทำงานอย่างที่คาดไว้
  4. ทำให้โค้ดของคุณสับสน

ประสบการณ์บอกว่า getElementById ในเบราว์เซอร์หลักจะส่งคืนองค์ประกอบแรกที่ตรงกันในเอกสาร แต่นี่อาจไม่ใช่กรณีในอนาคต

เมื่อ jQuery ได้รับ ID เช่น #foo จะใช้ getElementById และเลียนแบบพฤติกรรมนั้น หากคุณต้องหลีกเลี่ยงปัญหานี้ (มันน่าเศร้า) คุณสามารถใช้ $ (" * #foo") ซึ่งจะโน้มน้าวให้ jQuery ใช้ getElementsByTagName และส่งกลับรายการองค์ประกอบที่ตรงกันทั้งหมด

ฉันมักจะต้องเขียนโค้ดสำหรับเว็บไซต์อื่น ๆ และฉันต้องแก้ไขสิ่งนี้ ในโลกที่เป็นธรรมฉันไม่ต้องออกแบบฟังก์ชั่นใหม่เพื่อเริ่มต้นโดยตรวจสอบว่า ID นั้นไม่เหมือนใครหรือไม่ ID ควรไม่ซ้ำกันเสมอ โลกโหดร้ายและนั่นคือสาเหตุที่ฉันร้องไห้


5
คำตอบนี้ทำให้ฉันร้องไห้ ... เสียงหัวเราะ!
A1rPun

8

คุณสามารถทำสิ่งต่าง ๆ มากมาย - แต่นั่นไม่ได้หมายความว่าคุณควร

ในฐานะที่เป็นโปรแกรมเมอร์ (โดยทั่วไปจะพูด) เราสร้างชีวิตของเราให้มีความแม่นยำและปฏิบัติตามกฎ - นี่คือกฎที่ง่ายต่อการปฏิบัติซึ่งเป็นพื้นฐานพื้นฐานของสิ่งที่เราทำ - เราชอบ (ขึ้นอยู่) ตัวระบุเฉพาะภายในขอบเขตที่กำหนด ...

การทำลายกฎเป็นสิ่งที่เราทำได้เพราะเบราว์เซอร์รองรับเกินไป - แต่จริงๆแล้วเราทุกคนควรจะดีกว่าถ้าเบราว์เซอร์เข้มงวดเกี่ยวกับความต้องการรูปแบบที่ถูกต้องและ HTML ที่ถูกต้องความเจ็บปวดเล็กน้อยที่มันจะเกิดขึ้น ได้รับการชำระคืนแล้ว!

ดังนั้นมันแย่ขนาดนั้นจริงเหรอ? ในฐานะโปรแกรมเมอร์คุณจะถามได้อย่างไร อาชญากรรมต่ออารยธรรม (-:


ภาคผนวก:

คุณเขียนว่าเบราว์เซอร์รองรับเกินไปเหมือนเป็นเรื่องไม่ดี

ฉันทำเพราะเป็น - เราไม่ได้พูดถึงกฎที่ซับซ้อนเรากำลังพูดถึงการสร้างสิ่งต่าง ๆ ที่ดีและการใช้กฎที่สามารถทดสอบทางกลไกและในทางกลับกันทำให้ง่ายขึ้นสำหรับผลลัพธ์ที่จะดำเนินการทางกลไก หากเบราว์เซอร์มีความเข้มงวดเครื่องมือจะปรับตัวได้อย่างรวดเร็วเพื่อรองรับสิ่งนั้น - ไม่ใช่เช่นนั้นพวกเขาก็ไม่ได้ทำเช่นนั้น แค่คิดในเรื่องนี้ - อีเมลจะเป็นสื่อกลางที่ดีกว่าถ้า MS และ Netscape ไม่ได้เมาด้วยการอนุญาต HTML ที่ไม่ จำกัด เมื่อ "ภาษามาร์กอัปภาษาอีเมล" ที่ซับซ้อนน้อยกว่าด้วยการสนับสนุนข้อความที่ยกมาอย่างชัดเจน ... แต่เรือลำนั้นแล่นไปและในทำนองเดียวกันเราก็สามารถ 'ควรมี ) แต่เราทำไม่ได้


คุณเขียนว่าเบราว์เซอร์รองรับเกินไปเหมือนเป็นเรื่องไม่ดี แต่คุณไม่เชื่ออย่างนั้นหรือ
KaptajnKold

4
ฉันไม่สามารถพูดกับ Murph ได้ แต่ฉันคิดว่ามันเป็นสิ่งเลวร้ายจริงๆ จากนั้นอีกครั้งหากไม่มีการให้อภัยในระดับนี้เว็บอาจไม่มีแรงกระตุ้นที่จะเติบโตอย่างที่เรารู้
Andrea

1
@ Andrea: อินเทอร์เน็ตจะไม่เติบโตอย่างที่เรารู้ มันจะเติบโตช้ากว่า แต่มันก็จะมีพื้นฐานที่มั่นคงมากขึ้นของสิ่งที่เป็นและไม่ถูกต้องรหัส Fast-but-sloppy อาจใช้ได้ แต่ฉันชอบช้ากว่ามาก แต่ถูกต้อง โดยเฉพาะอย่างยิ่งเนื่องจากไม่ใช่ว่าเราต้องการพูดถึงการเติบโตเพียงไม่กี่ปี
Nicol Bolas

3
@ Andrea ฉันพนันได้เลยว่ามันจะเติบโตขึ้นอย่างรวดเร็ว - เครื่องมือจะพัฒนาเพื่อจัดการกับปัญหา ในหลาย ๆ กรณีเครื่องมือเป็นสาเหตุของมาร์กอัปที่ไม่ดี ความจริงก็คือผู้คนมักจะทำสิ่งที่จำเป็นน้อยที่สุด - ขั้นตอนในการ "ทำดี" นั้นค่อนข้างเล็กและง่ายพอที่จะทดสอบและบังคับใช้และผู้คนจะได้รับการช่วยเหลือโดยไม่เครียด
Murph

1
ไม่น่ากลัวที่เบราว์เซอร์รองรับ มันเป็นที่น่ากลัวว่าพวกเขากำลังรองรับทั้งหมดในรูปแบบที่แตกต่างกัน
Dan Ray

7

ในการเขียนสคริปต์: getElementByIDจะกลับเฉพาะการแข่งขันครั้งแรก ใน CSS: #idจะมีผลกับองค์ประกอบทั้งหมดด้วย ID นั้น ใน Browser Render จะไม่มีผลกระทบใด ๆ

นี่คือพฤติกรรมของมาตรฐาน w3c ไม่ใช่สิ่งที่เป็นไปได้ แต่เป็นสิ่งที่กำหนดไว้

https://dom.spec.whatwg.org/#interface-nonelementparentnode


7
นี่เป็นพฤติกรรมหนึ่งที่เป็นไปได้ getElementByIdสามารถคืนองค์ประกอบใด ๆ ได้อย่างสมบูรณ์แบบหรือแม้กระทั่งวัตถุว่าง ผล CSS สามารถอยู่ในองค์ประกอบใด ๆ หรือไม่มีหรือทั้งหมด หรือเบราว์เซอร์อาจมีปัญหา จากมาตรฐานพฤติกรรมไม่ได้กำหนด
rds

2
มันไม่ได้มาตรฐานเพราะมาตรฐานระบุสิ่งที่ต้องทำในสถานการณ์เหล่านั้น ดังนั้นไม่ getElementById ไม่สามารถส่งคืนองค์ประกอบใด ๆ ได้มาตรฐานระบุอย่างชัดเจนว่าฉันจะส่งคืนการจับคู่ครั้งแรก ฉันยอมรับว่าพฤติกรรมจากมาตรฐานไม่ได้กำหนดสิ่งที่คุณไม่เข้าใจคือกรณีเหล่านั้นทั้งหมดเป็นส่วนหนึ่งของมาตรฐาน
Bart Calixto

1
คำตอบนี้จะค่อนข้างดีกว่าถ้ามันรวมอ้างอิงอ้างอิงส่วนที่เกี่ยวข้องของมาตรฐาน (หรืออย่างน้อยหมายเลขส่วน)
yoniLavi

2
@yoniLavi อัพเดทแล้ว
Bart Calixto

2
ขอบคุณ @Bart คุณพูดถูกจริง ๆ :) มาตรฐานบอกว่า "คืนองค์ประกอบแรกภายในการสืบทอดของโหนดที่มี ID คือ elementId"
yoniLavi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.