Dwa elementy HTML z tym samym atrybutem id: Jak naprawdę jest źle?

122

Po prostu przeglądam kod źródłowy map Google. W nagłówku mają 2 div z id = "search", jeden zawiera drugi, a także ma atrybut jstrack = "1". Istnieje forma oddzielająca je w ten sposób:

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

Ponieważ to jest Google, zakładam, że to nie pomyłka.

Więc jak źle może być naruszanie tej zasady? Tak długo, jak jesteś ostrożny w wyborze css i dom, dlaczego nie użyć ponownie identyfikatorów podobnych do klas? Czy ktoś robi to celowo, a jeśli tak, to dlaczego?

Danludwig
źródło
102
„Ponieważ jest to Google, zakładam, że to nie pomyłka”. -> Google nie są nieomylne. Popełniają błędy jak my wszyscy.
Joeri Sebrechts
43
w rzeczywistości faceci z Google mają SZUKAJ w głowie, więc nie mogą myśleć o żadnym innym identyfikatorze: P
Pankaj Upadhyay
10
Mam wrażenie, że ta strona jest renderowana z różnych fragmentów HTML, więc jeden programista w jednym fragmencie użył tego identyfikatora i to samo stało się z innym programistą w innym fragmencie.
Luciano
10
Całe pytanie „jak źle to naprawdę” przypomina mi o tym: xkcd.com/292
Daniel Roseman
3
@DanielRoseman xkcd robi to również: what-if.xkcd.com/23/#question
SQB

Odpowiedzi:

140

Specyfikacja mówi UNIKALNE

Specyfikacja HTML 4.01 mówi, że identyfikator musi być unikalny dla całego dokumentu.

Specyfikacja HTML 5 mówi to samo, ale innymi słowy. Mówi, że identyfikator musi być unikalny w swoim poddrzewie macierzystym , co jest w zasadzie dokumentem, jeśli czytamy jego definicję .

Unikaj powielania

Ale ponieważ renderery HTML bardzo wybaczają, jeśli chodzi o renderowanie HTML, dopuszczają duplikaty identyfikatorów. Należy tego unikać, jeśli jest to w ogóle możliwe i ściśle unikać, gdy programowo uzyskuje się dostęp do elementów za pomocą identyfikatorów w JavaScript. Nie jestem pewien, która getElementByIdfunkcja powinna zostać zwrócona po znalezieniu kilku pasujących elementów? Czy to powinno:

  • zwrócić błąd?
  • zwrócić pierwszy pasujący element?
  • zwrócić ostatni pasujący element?
  • zwrócić zestaw pasujących elementów?
  • nic nie zwracać?

Ale nawet jeśli przeglądarki działają obecnie niezawodnie, nikt nie może zagwarantować takiego zachowania w przyszłości, ponieważ jest to niezgodne ze specyfikacją. Dlatego zalecamy, aby nigdy nie kopiować identyfikatorów w tym samym dokumencie.

Robert Koritnik
źródło
1
@missingno: Dodałem link do specyfikacji HTML 5, który mówi o tym samym, ale w innym brzmieniu.
Robert Koritnik
6
Zgodnie ze specyfikacją DOM „jeśli więcej niż jeden element ma atrybut ID o tej wartości, zwracane jest niezdefiniowane” (co oznacza, że ​​nie ma zdefiniowanego „poprawnego” wyniku, a nie rzeczywistą wartość undefined). Rzadko warto polegać na niezdefiniowanym zachowaniu.
samotny poniedziałek
1
Warto zauważyć, że w HTML5 ten data-atrybut jest przydatny, gdy można pokusić się o przypisanie wielu rzeczy tego samego identyfikatora. Dzięki temu możesz mieć wiele różnych identyfikatorów z jednym wspólnym data-somethingatrybutem. Mimo to wszystkie przeglądarki, które znam, ignorują nieznane atrybuty, więc prawdopodobnie są bezpieczne w prawie każdej nowoczesnej przeglądarce bez pełnego wsparcia HTML.
Tim Post
2
@ JoachimSauer: Kiedy używasz atrybutów danych, możesz mieć pary klucz-wartość, co nie jest prawdą, gdy używasz klas CSS. W takim przypadku wszystkie są jak właściwości logiczne. Element ma klasę CSS lub nie. Jeśli chcesz wartości z klasami CSS, musisz jakoś połączyć je w nazwę klasy CSS i przeanalizować to później. Mam nadzieję, że zobaczysz teraz zalety korzystania z dataatrybutów. Są także obsługiwane bezpośrednio przez jQuery, gdy po prostu odwołujesz się do data-something="123"atrybutu $(elem).data("something").
Robert Koritnik
1
@RobertKoritnik: Oczywiście! Nie myślałem o tym przypadku użycia. Myślałem tylko o sprawie id="search".
Joachim Sauer
30

Zapytałeś „jak źle”. Tak więc, aby udzielić trochę odpowiedzi (całkowicie trafnej) @ RobertKoritnik ...

Ten kod jest niepoprawny. Niepoprawne nie występuje w odcieniach szarości. Ten kod narusza standard i dlatego jest nieprawidłowy. Nie sprawdziłby sprawdzania poprawności i powinien.

To powiedziawszy, żadna przeglądarka obecnie na rynku nie narzekałaby na to ani nie miała z tym żadnego problemu. Przeglądarki będą miały prawo narzekać na to, ale żadna z obecnych wersji żadnej z nich obecnie tego nie robi. Co nie oznacza, że ​​przyszłe wersje mogą nie traktować tego kodu źle.

Twoje zachowanie przy próbie użycia tego identyfikatora jako selektora, zarówno w css, jak i javascript, jest niewyobrażalne i prawdopodobnie różni się w zależności od przeglądarki. Przypuszczam, że można by przeprowadzić badanie, aby zobaczyć, jak reaguje na to każda przeglądarka. Myślę, że w najlepszym przypadku potraktowałoby to tak jak „class =” i wybrało ich listę. (Może to jednak mylić biblioteki JavaScript - gdybym był autorem jQuery, mógłbym zoptymalizować kod selektora, aby jeśli przyszedłeś do mnie z selektorem rozpoczynającym się od „#”, spodziewam się pojedynczego obiektu i otrzymania lista może mnie całkowicie zepsuć.)

Może także wybrać pierwszy, ewentualnie ostatni, albo nie wybrać żadnego z nich, albo całkowicie zawiesić przeglądarkę. Nie można tego powiedzieć bez wypróbowania.

„Jak źle” zależy wtedy całkowicie od tego, jak ściśle konkretna przeglądarka implementuje specyfikację HTML i co robi, gdy zostanie skonfrontowana z naruszeniem tej specyfikacji.

EDYCJA: Właśnie tego dzisiaj spotkałem. Pobieram różne komponenty z formularzy wyszukiwania różnych typów podmiotów, aby stworzyć świetne, kompleksowe narzędzie do raportowania dla tej witryny, ładuję formularze wyszukiwania zdalnych stron w ukrytych divach i umieszczam je w mojej generator raportów, gdy jako źródło raportu zostanie wybrany odpowiedni typ encji. Jest więc ukryta wersja formularza i wersja wyświetlana w generatorze raportów. JavaScript, który został dostarczony, we wszystkich przypadkach, odnosi się do elementów według identyfikatora, których na stronie znajdują się teraz DWIE - ukryty i wyświetlany.

Wydaje się, że jQuery wybiera PIERWSZĄ, która we wszystkich przypadkach jest dokładnie tą, której NIE chcę.

Pracuję nad tym, pisząc selektory, aby określić region strony, w której chcę uzyskać moje pole (tj .: $ ('# containerDiv #specificElement')). Ale jest jedna odpowiedź na twoje pytanie - jQuery w Chrome zdecydowanie zachowuje się w określony sposób w przypadku naruszenia tego specyfikacji.

Dan Ray
źródło
... powiązane pytanie: stackoverflow.com/q/29295824/287948 na temat obowiązku posiadania identyfikatorów w szybkim profilu CSS.
Peter Krauss,
3
„Niepoprawne nie występuje w odcieniach szarości”. Często to widzę i jest to jedna z tych rzeczy, które są technicznie poprawne, ale nie są „prawdziwe” w życiu ani w programowaniu. Pośrednio omawiasz to całkiem dokładnie w swojej odpowiedzi i mógłbym wyjaśnić, ale ta scena z teorii Wielkiego Wybuchu wykonuje tak dobrą robotę, że pozwolę, aby przemówiła za mnie i mam nadzieję, że ktoś się roześmie ... Stuart kontra Sheldon youtube.com/ oglądać? v = F_1zoX5Ax9U
Night Owl
to jest 8-letnia odpowiedź, ale myślę, że to bardzo niezrównoważone, jak hiperbolujesz na pytanie OP, ale nie narzekasz zbytnio na liberalne i niebezpieczne zachowanie przeglądarek w związku z powtarzającymi się identyfikatorami, co jest znacznie gorsze niż to, co OP próbuje zrobić.
erandros
20

Jak źle to naprawdę jest?

  1. To sprawia że płaczę
  2. To jest nieważne
  3. Wiele bibliotek javascript nie będzie działać zgodnie z oczekiwaniami
  4. Sprawia, że ​​Twój kod jest mylący

Doświadczenie mówi, że getElementById w głównych przeglądarkach zwróci pierwszy dopasowany element w dokumencie. Ale nie zawsze może tak być w przyszłości.

Gdy jQuery otrzymuje identyfikator np. #Foo, używa getElementById i naśladuje to zachowanie. Jeśli musisz obejść ten problem (to smutne), możesz użyć $ („ * #foo”), co przekona jQuery do użycia getElementsByTagName i zwróci listę wszystkich pasujących elementów.

Często muszę pisać kod dla innych stron i muszę to obejść. W sprawiedliwym świecie nie musiałbym przeprojektowywać funkcji, aby zacząć od sprawdzenia, czy identyfikator jest unikalny. Identyfikatory powinny zawsze być unikalne. Świat jest okrutny i dlatego płaczę.

ColBeseder
źródło
5
Ta odpowiedź wywołała u mnie płacz ... śmiechu!
A1rPun
8

Państwo może zrobić wiele rzeczy - ale to nie znaczy, że powinieneś.

Jako programista (ogólnie rzecz biorąc) budujemy nasze życie na precyzji i przestrzeganiu zasad - oto zasada, którą można łatwo zastosować, która jest dość podstawowa dla tego, co robimy - lubimy (zależymy od) unikalnych identyfikatorów w danym zakresie ...

Łamanie reguły jest czymś, co możemy zrobić, ponieważ przeglądarka jest zbyt dostosowana - ale naprawdę byłoby lepiej, gdyby przeglądarki ściśle wymagały dobrze sformułowanego i poprawnego HTML, niewielka ilość bólu, którą spowodowałaby, dawno by został spłacony!

Czy to naprawdę takie złe? Jako programista, jak możesz w ogóle zapytać? Jest to przestępstwo przeciwko cywilizacji (-:


Uzupełnienie:

Piszesz, że przeglądarki są zbyt przychylne, jakby to była zła rzecz

Robię to, ponieważ tak jest - nie mówimy o skomplikowanych regułach, mówimy zasadniczo o tym, aby rzeczy były dobrze uformowane i w inny sposób stosować reguły, które można testować mechanicznie, a które z kolei ułatwiają mechaniczne przetwarzanie wyniku. Gdyby przeglądarki były surowe, narzędzia bardzo szybko dostosowałyby się do obsługi tego - nie było tak, że nie zrobiły tego, niektóre w takim stopniu, w jakim wykorzystują to niepowodzenie. Pomyśl o tym - e-mail byłby o wiele ładniejszym medium, gdyby MS i Netscape nie spieprzyły go, pozwalając na nieograniczony HTML, gdy znacznie mniej złożony „język znaczników e-mail” z wyraźną obsługą cytowanego tekstu dałby nam znacznie lepsze narzędzie ... ale ten statek płynął i podobnie możemypowinniśmy ), ale nie możemy

Murph
źródło
Piszesz, że przeglądarki są zbyt przychylne, jakby to było złe, ale na pewno w to nie wierzysz?
KaptajnKold
4
Nie mogę mówić w imieniu Murpha, ale z pewnością uważam, że to naprawdę zła rzecz. Z drugiej strony, bez tego poziomu przebaczenia sieć mogłaby nie mieć impulsu, by rosnąć tak, jak my ją znamy.
Andrea
1
@Andrea: Internet nie urósłby tak, jak wiemy. Rośnie wolniej. Ale miałaby też solidniejszą podstawę do tego, co jest i nie jest poprawnym kodem. Szybka, ale niechlujna może działać, ale wolę wolniejszą, ale poprawną. Zwłaszcza, że ​​nie jest tak, że rozmawiamy o kilku latach wzrostu.
Nicol Bolas,
3
@Andrea Założę się, że urósłby on prawie tak szybko - narzędzia ewoluowałyby, aby poradzić sobie z tym problemem. Podczas gdy w wielu przypadkach narzędzia były główną przyczyną złych znaczników. Faktem jest, że ludzie robią to, co najmniej konieczne - krok do „dobrze wykształconego” jest stosunkowo niewielki i wystarczająco łatwy do przetestowania i egzekwowania, a ludzie
zaakceptowaliby
1
Przeglądarki nie są straszne. To okropne, że wszyscy są nastawieni na różne sposoby .
Dan Ray
7

W skryptach: getElementByIDzwróci tylko pierwsze dopasowanie. W CSS: #idwpłynie na WSZYSTKIE elementy o tym identyfikatorze. Renderowanie w przeglądarce nie przyniesie żadnego efektu.

Takie jest zachowanie standardu w3c. Nie jest to możliwe, to jest faktyczne.

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

Bart Calixto
źródło
7
To jest możliwe zachowanie. getElementByIdmoże idealnie zwrócić dowolny element, a nawet zerowy obiekt. Efekt CSS może występować na dowolnych elementach lub na żadnym z nich lub na wszystkich. Lub przeglądarka może ulec awarii. Niestandardowe zachowanie jest niezdefiniowane
rds
2
Nie jest to poza standardem, ponieważ standard określa, co robić w takich sytuacjach. Więc nie, getElementById nie mógł zwrócić żadnego elementu, standard mówi wyraźnie, że zwrócę pierwsze dopasowanie. Zgadzam się, że zachowanie poza standardem jest niezdefiniowane, nie rozumiesz tego, że wszystkie te przypadki są częścią standardu.
Bart Calixto,
1
Ta odpowiedź byłaby nieco lepsza, gdyby faktycznie zawierała, jako odniesienie, cytat odpowiedniej części normy (lub przynajmniej numer sekcji).
yoniLavi
2
@yoniLavi zaktualizowane.
Bart Calixto,
2
Dzięki @Bart. Masz absolutną rację :) Standard mówi „Zwraca pierwszy element potomków węzła, którego ID to elementId”.
yoniLavi