Atributos personalizados - Sim ou não?

254

Recentemente, tenho lido cada vez mais sobre pessoas que usam atributos personalizados em suas tags HTML, principalmente com o objetivo de incorporar alguns bits extras de dados para uso no código javascript.

Eu esperava reunir algum feedback sobre se o uso de atributos personalizados é ou não uma boa prática e também quais são algumas alternativas.

Parece que pode realmente simplificar o código do servidor e do cliente, mas também não é compatível com o W3C.

Deveríamos usar atributos HTML personalizados em nossos aplicativos da web? Por que ou por que não?

Para quem acha que os atributos personalizados são uma coisa boa: quais são algumas das coisas que você deve ter em mente ao usá-los?

Para aqueles que pensam que atributos personalizados são algo ruim: quais alternativas você usa para realizar algo semelhante?

Atualização: Estou interessado principalmente no raciocínio por trás dos vários métodos, bem como aponta por que um método é melhor que outro. Eu acho que todos nós podemos criar 4-5 maneiras diferentes de realizar a mesma coisa. (elementos ocultos, scripts embutidos, classes extras, informações de análise de IDs etc.).

Atualização 2: Parece que o data-recurso de atributo HTML 5 tem muito suporte aqui (e eu tendem a concordar, parece uma opção sólida). Até agora, não vi muitas refutações nessa sugestão. Existem problemas / armadilhas para se preocupar em usar essa abordagem? Ou é simplesmente uma invalidação "inofensiva" das especificações atuais do W3C?

TM.
fonte
Honestamente, minha posição inicial é que eles não são uma coisa tão ruim, o que pode ser bastante controverso com os puristas. No entanto, sinto que realmente preciso me sentar e avaliar todas as opções disponíveis para respaldar isso adequadamente, portanto, a necessidade de escrever o longo ensaio.
Paolo Bergantino
Para fazer isso, você pode precisar apenas de alguns contra-exemplos: do que você está tentando implementar, como é conveniente fazer isso com atributos personalizados e por que essa solução é melhor e não é pior do que outras soluções sem atributos personalizados.
21420 ChrisW
@ Chrishr Estou perguntando principalmente por interesse, não por alguma aplicação específica.
TM.
Bem, existem muitas opções para obter os dados para o lado do cliente: campos de entrada ocultos, listas de definições ocultas, classes, plug-ins de metadados, com um enorme dicionário Javascript (objeto) com todo o mapeamento de dados separadamente, atributos personalizados, atributos de dados ( HTML5) etc. Desejo explorar tudo isso, considerar seus méritos, suas armadilhas e finalmente chegar a uma conclusão. Este post foi finalmente me convencer a começar a escrever este. :) deve ser feito em algum momento antes de 2010.
Paolo Bergantino
2
@Paolo, você não pode simplesmente dizer que escreveu um ensaio respondendo a essa pergunta sem fornecer o link. Não é legal.
Connell

Respostas:

253

O HTML 5 permite explicitamente atributos personalizados que começam com data. Então, por exemplo, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p>é válido. Como é oficialmente suportado por um padrão, acho que essa é a melhor opção para atributos personalizados. E não exige que você sobrecarregue outros atributos com hacks, para que seu HTML possa permanecer semântico.

Fonte: http://www.w3.org/TR/html5/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes

Mandril
fonte
Essa é uma boa abordagem. Mas duvido que funcione, pois você precisa suportar o IE 6 e outros navegadores antigos.
cllpse
8
Tenho certeza de que funciona com navegadores mais antigos; os atributos são adicionados ao DOM, onde você pode acessá-los.
Ms2ger
12
Funciona perfeitamente bem com todos os navegadores usando o método getAttribute () em um HTMLElement. Além disso, como HTML5 dataset apoio cresce, você pode facilmente adicionar que no.
AJM
1
@ Chuck, aparentemente, você pode adicionar Atributos ao DOCTYPE: rodsdot.com/html/… - não que eu ache que seja uma boa ideia, mas pareça padronizada.
Michael Stum
2
@Wahnfrieden: w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8, que é o método aprovado e compatível com os padrões. O que é bem descrito e demonstrado aqui: rodsdot.com/html/… Como publicado anteriormente por outras pessoas.
Rdivilbiss
95

Aqui está uma técnica que eu tenho usado recentemente:

<div id="someelement">

    <!-- {
        someRandomData: {a:1,b:2},
        someString: "Foo"
    } -->

    <div>... other regular content...</div>
</div>

O objeto de comentário está vinculado ao elemento pai (por exemplo, #someelement).

Aqui está o analisador: http://pastie.org/511358

Para obter os dados para qualquer elemento específico, basta chamar parseDatacom uma referência ao elemento passado como o único argumento:

var myElem = document.getElementById('someelement');

var data = parseData( myElem );

data.someRandomData.a; // <= Access the object staight away

Pode ser mais sucinto do que isso:

<li id="foo">
    <!--{specialID:245}-->
    ... content ...
</li>

Acesse isso:

parseData( document.getElementById('foo') ).specialID; // <= 245

A única desvantagem de usar isso é que ele não pode ser usado com elementos de fechamento automático (por exemplo <img/>), pois os comentários devem estar dentro do elemento a ser considerado como dados desse elemento.


EDIT :

Benefícios notáveis ​​desta técnica:

  • Fácil de implementar
  • Será que não invalidate HTML / XHTML
  • Fácil de usar / entender (notação JSON básica)
  • Discreto e semanticamente mais limpo que a maioria das alternativas

Aqui está o código do analisador (copiado do hiperlink http://pastie.org/511358 acima, caso ele se torne indisponível no pastie.org):

var parseData = (function(){

    var getAllComments = function(context) {

            var ret = [],
                node = context.firstChild;

            if (!node) { return ret; }

            do {
                if (node.nodeType === 8) {
                    ret[ret.length] = node;
                }
                if (node.nodeType === 1) {
                    ret = ret.concat( getAllComments(node) );
                }
            } while( node = node.nextSibling );

            return ret;

        },
        cache = [0],
        expando = 'data' + +new Date(),
        data = function(node) {

            var cacheIndex = node[expando],
                nextCacheIndex = cache.length;

            if(!cacheIndex) {
                cacheIndex = node[expando] = nextCacheIndex;
                cache[cacheIndex] = {};
            }

            return cache[cacheIndex];

        };

    return function(context) {

        context = context || document.documentElement;

        if ( data(context) && data(context).commentJSON ) {
            return data(context).commentJSON;
        }

        var comments = getAllComments(context),
            len = comments.length,
            comment, cData;

        while (len--) {
            comment = comments[len];
            cData = comment.data.replace(/\n|\r\n/g, '');
            if ( /^\s*?\{.+\}\s*?$/.test(cData) ) {
                try {
                    data(comment.parentNode).commentJSON =
                        (new Function('return ' + cData + ';'))();
                } catch(e) {}
            }
        }

        return data(context).commentJSON || true;

    };

})();
James
fonte
2
Por curiosidade, que método você usa para tags de fechamento automático? Geralmente, preciso usar algo assim nos elementos <input> (para ajudar nas regras de validação do lado do cliente). Que alternativa você toma nessa situação?
TM.
2
Eu provavelmente usaria uma técnica semelhante, em vez de os dados do comentário vinculados ao "parentNode" poderem se vincular ao "previousSibling" do comentário ... Então você poderia ter o comentário imediatamente após o <input /> e trabalho: <input /> <! - {data: 123} -> #
James
7
alguém deve fazer deste um plugin jQuery
SeanDowney
10
Os comentários devem poder ser alterados / excluídos sem quebrar nada. Esse é o ponto. Portanto, é uma má idéia colocar algo importante na marcação ou no código nos comentários. Os desenvolvedores futuros podem facilmente pensar que são comentários e excluí-los. Já temos uma solução real para essa pergunta: atributos personalizados prefixados com "data-". Essa abordagem nunca deve ser usada.
precisa saber é o seguinte
6
Deixe-me reforçar a declaração de @MGOwen: não use comentários para adicionar funcionalidade. Especialmente no HTML. Você não está usando minifiers? Você não poderá remover comentários sem quebrar seu código. Isso também significa que você não pode mais adicionar comentários reais.
Olivictor
15

Você pode criar qualquer atributo se especificar um esquema para sua página.

Por exemplo:

Adicione isso

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:addthis="http://www.addthis.com/help/api-spec">
...
<a addthis:title="" addthis:url="" ...>

Facebook (tags pares)

<html xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml">
...
<fb:like href="http://developers.facebook.com/" width="450" height="80"/>
BrunoLM
fonte
10

A maneira mais fácil de evitar o uso de atributos personalizados é usar os atributos existentes.

use nomes de classe significativos e relevantes.
Por exemplo, faça algo como: type='book'e type='cd', para representar livros e CDs. As aulas são muito melhores para representar o que algo é .

por exemplo class='book'

Eu usei atributos personalizados no passado, mas honestamente, realmente não há necessidade deles, se você usar os atributos existentes de uma maneira semanticamente significativa.

Para dar um exemplo mais concreto, digamos que você tenha um site fornecendo links para diferentes tipos de lojas. Você pode usar o seguinte:

<a href='wherever.html' id='bookstore12' class='book store'>Molly's books</a>
<a href='whereverelse.html' id='cdstore3' class='cd store'>James' Music</a>

o estilo css pode usar classes como:

.store { }
.cd.store { }
.book.store { }

No exemplo acima, vemos que ambos são links para lojas (em oposição aos outros links não relacionados no site) e um é uma loja de CDs e o outro é uma livraria.

Jonathan Fingland
fonte
4
Bom ponto, mas, para ser justo, "type" é válido apenas em determinadas tags e, quando é um atributo válido, também possui uma lista de valores válidos; portanto, você ainda não é realmente compatível com o w3c.
TM.
1
meu ponto era que você NÃO deve usar a tag de tipo para isso. daí o Se você fosse ... então você deve ... Vou editar para fazer essa clara
Jonathan Fingland
Eu costumo fazer meus atributos de "classe" com sabores, acrescentando alguns deles a algum tipo de "qualificador-". para divs relacionados apenas ao layout, a classe seria "layout-xxx" ou para divs internos que envolvem uma parte importante, como um livro ou uma loja, eu teria um livro de conteúdo ou loja de conteúdo . então, no meu JavaScript, tenho uma função que precede essas coisas na tag com base no que estou procurando. ajuda a manter as coisas limpas e organizadas para mim, mas requer um certo nível de disciplina e pré-organização.
Ape-inago 14/06/2009
2
@ Jonathan, a coisa de classe dupla funciona muito bem, exceto nos casos em que os 'valores' não são conhecidos. Por exemplo, se é algum tipo de ID inteiro, não podemos muito bem selecionar para todos os casos possíveis. Em seguida, somos deixados para analisar o atributo de classe manualmente, o que é definitivamente viável, mas não tão claro no código e, em alguns casos, pode ser muito lento (se houver muitos elementos candidatos a serem analisados).
TM.
2
infelizmente, escrever seletores de css para duas classes ao mesmo tempo (.ab observe o espaço em branco ausente) não funciona no IE. ele funciona no Firefox e em outros navegadores. Ainda assim, o uso de classes é uma ótima maneira de significado semântico adicional incorporar a sua marcação
knittl
6

Incorpore os dados no dom e use metadados para jQuery .

Todos os bons plug-ins suportam o plug-in de metadados (permitindo opções por tag).

Também permite estruturas de dados / dados infinitamente complexas, bem como pares de valores-chave.

<li class="someclass {'some': 'random,'json':'data'} anotherclass">...</li>

OU

<li class="someclass" data="{'some':'random', 'json': 'data'}">...</li>

OU

<li class="someclass"><script type="data">{"some":"random","json":"data"}</script> ...</li>

Em seguida, obtenha os dados da seguinte maneira:

var data = $('li.someclass').metadata();
if ( data.some && data.some == 'random' )
alert('It Worked!');
antony.trupe
fonte
22
A corrupção do atributo de classe quando existe uma maneira aprovada pelo W3C de especificar atributos personalizados é provavelmente o motivo pelo qual você foi rejeitado.
Rdivilbiss 19/10/10
2
corromper o atributo de classe é apenas uma das maneiras de usar o plugin; não é o único caminho.
precisa saber é o seguinte
1
Outro motivo pelo qual você foi rejeitado é sugerir um plug-in no qual nenhum plug-in é necessário.
meandre 14/09/16
4

Não vejo problema em usar os recursos XHTML existentes sem quebrar nada ou estender seu espaço para nome. Vamos dar uma olhada em um pequeno exemplo:

<div id="some_content">
 <p>Hi!</p>
</div>

Como adicionar informações adicionais a some_content sem atributos adicionais? Que tal adicionar outra tag como a seguinte?

<div id="some_content">
 <div id="some_content_extended" class="hidden"><p>Some alternative content.</p></div>
 <p>Hi!</p>
</div>

Ele mantém a relação por meio de um id / extensão bem definido "_extended" de sua escolha e por sua posição na hierarquia. Costumo usar essa abordagem em conjunto com o jQuery e sem realmente usar técnicas semelhantes ao Ajax.

merkuro
fonte
2
O problema com a adição de tags aninhadas como esta é que ela tende a criar código MUITO complicado e feio do servidor (JSP / ASP / DTL etc)
TM.
3

Não. Tente algo assim:

<div id="foo"/>

<script type="text/javascript">
  document.getElementById('foo').myProperty = 'W00 H00! I can add JS properties to DOM nodes without using custom attributes!';
</script>
Anon
fonte
1
Então, você prefere escrever muitas tags de script extras em todo o documento para páginas dinâmicas? Eu usaria atribuições manuais de javascript quando as informações são adicionadas no lado do cliente, mas esse problema é principalmente sobre o que renderizar no servidor. Além disso, jQuery.data () é muito melhor que o seu método.
TM.
A resposta acima é um exemplo elaborado e independente da estrutura para demonstrar a funcionalidade. Você pode facilmente expandir sua essência para tornar o código bastante conciso. Por exemplo, <div id = "foo" /> <div id = "bar" /> <div id = "baz" /> <tipo de script = "text / javascript"> xtrnlFnc ({foo: 'w00 h00', bar : 'etc.', baz: 3.14159}); </script> Se você estiver usando jQuery (não que você tenha mencionado na sua pergunta original), use todos os métodos de dados - é para isso que serve. Caso contrário, a transmissão de dados entre as camadas da arquitetura é um uso perfeitamente válido de tags de script embutidas.
Anon
É definitivamente uma opção óbvia e válida. Na minha opinião, apenas confunde o código muito mais do que muitas outras alternativas que não usam atributos personalizados. E só para esclarecer, não estou tentando ser agressivo ou rude, apenas estou tentando persuadir alguns dos seus raciocínios, por que você prefere esse método. Você forneceu uma alternativa, mas não é exatamente disso que se trata.
TM.
1
Eu não acho que haja um problema com essa abordagem de quebrar os navegadores. A Microsoft usa esse mecanismo exato como mecanismo preferido nas páginas do ASP.NET. (chamando RegisterExpandoAttribute no lado do servidor). A questão parece focada no cliente e não no servidor, mas no lado do servidor todas essas abordagens podem ser (deveriam ser?) Abstraídas.
Adrian
3
Os profissionais dessa abordagem: - Produz marcação válida (mesmo em navegadores / especificações antigos). - Torna clara a intenção dos dados (a serem consumidos pelo JS). - É coesa com o elemento sem fazer uso inteligente de outros recursos (como comentários). --Não requer análise especial. Do ponto de vista do servidor, você pode pensar nisso como um RPC.
precisa
2

Não estou usando atributos personalizados, porque estou produzindo XHTML, porque quero que os dados sejam legíveis por máquina por software de terceiros (embora eu possa estender o esquema XHTML, se quiser).

Como alternativa aos atributos personalizados, na maioria das vezes estou encontrando os atributos id e class (por exemplo, como mencionado em outras respostas) suficientes.

Além disso, considere o seguinte:

  • Se os dados extras devem ser legíveis por humanos e legíveis por máquina, eles precisam ser codificados usando tags e texto HTML (visíveis) em vez de como atributos personalizados.

  • Se não precisar ser legível por humanos, talvez possa ser codificado usando tags e texto HTML invisíveis .

Algumas pessoas abrem uma exceção: elas permitem atributos personalizados, adicionados ao DOM por Javascript no lado do cliente em tempo de execução. Eles acham que isso é bom: como os atributos personalizados são adicionados apenas ao DOM no tempo de execução, o HTML não contém atributos personalizados.

ChrisW
fonte
1

Criamos um editor baseado na Web que entende um subconjunto de HTML - um subconjunto muito rigoroso (que é entendido quase universalmente pelos clientes de email). Precisamos expressar coisas como <td width="@INSWIDTH_42@">no banco de dados, mas não podemos tê-lo no DOM, caso contrário, o navegador em que o editor é executado fica em pânico (ou é mais provável que fique em pânico do que em atributos personalizados) . Como queríamos arrastar e soltar, colocá-lo puramente no DOM, assim como o jquery .data()(os dados extras não foram copiados corretamente). Provavelmente também precisávamos de dados extras para o passeio .html(). No final, decidimos usar <td width="1234" rs-width="@INSWIDTH_42@">durante o processo de edição e, quando publicamos tudo, removemos widthe fazemos uma pesquisa e destruição de expressões regulares s/rs-width=/width=/g.

No começo, o cara que escrevia a maior parte disso era o nazi de validação e tentava de tudo para evitar nosso atributo personalizado, mas no final concordou quando nada mais parecia funcionar para TODOS os nossos requisitos. Ajudou quando ele percebeu que o atributo personalizado nunca apareceria em um email . Consideramos codificar nossos dados extras emclass , mas decidimos que esse seria o maior dos dois males.

Pessoalmente, prefiro deixar tudo limpo e passar por validadores, etc., mas como funcionário da empresa, devo lembrar que minha principal responsabilidade é promover a causa da empresa (ganhar tanto dinheiro o mais rápido possível), não o desejo egoísta de pureza técnica. As ferramentas devem funcionar para nós; não nós por eles.

Bernd Jendrissek
fonte
1

Eu sei que as pessoas são contra, mas eu vim com uma solução super curta para isso. Se você deseja usar um atributo personalizado como "meu", por exemplo:

<a href="test.html" mine-one="great" mine-two="awesome">Test</a>

Em seguida, você pode executar esse código para recuperar um objeto da mesma forma que jquery.data ().

var custom_props = {} ;
$.each($(".selector")[0].attributes, function(i,x) {
    if (this.specified && x.name.indexOf("mine-") !== -1) 
        self.new_settings[x.name.replace("modal-","")] = x.value;
});
agrublev
fonte
0

Especificação: Crie um controle ASP.NET TextBox que formata automaticamente seu texto como um número, de acordo com as propriedades "DecimalSeparator" e "ThousandsSeparator", usando JavaScript.


Uma maneira de transferir essas propriedades do controle para JavaScript é fazer com que o controle processe propriedades personalizadas:

<input type="text" id="" decimalseparator="." thousandsseparator="," />

Propriedades personalizadas são facilmente acessíveis por JavaScript. E enquanto uma página usando elementos com propriedades personalizadas não for validada , a renderização dessa página não será afetada.


I única usar essa abordagem quando eu quero associar tipos simples, como strings e inteiros para elementos HTML para uso com JavaScript. Se eu quiser facilitar a identificação dos elementos HTML, utilizarei as propriedades de classe e identificação .

cllpse
fonte
0

Para aplicativos Web complexos, descarto atributos personalizados em todo o lugar.

Para páginas mais públicas, eu uso o atributo "rel" e despejo todos os meus dados no JSON e, em seguida, decodificá-lo com MooTools ou jQuery:

<a rel="{color:red, awesome:true, food: tacos}">blah</a>

Ultimamente, estou tentando manter o atributo de dados HTML 5 apenas para "preparar", mas ele ainda não veio naturalmente.

Ryan Florence
fonte
-1

Eu uso campos personalizados o tempo todo, por exemplo, <ai = "" .... Então faça referência a i com jquery. HTML inválido, sim. Funciona bem, sim.

Marius
fonte
Algo parece que está faltando aqui. Sua tag foi concluída aqui?
Stuart Siegler
Como alguém pode entender isso? Por favor, complete sua resposta.
Rahul Raj
-2

Atributos personalizados, na minha humilde opinião, não devem ser usados, pois não são validados. Como alternativa, você pode definir muitas classes para um único elemento, como:

<div class='class1 class2 class3'>
    Lorem ipsum
</div>
Alan Haggai Alavi
fonte
10
pessoalmente, acho que este é um exemplo terrível. seus nomes de classe definem a aparência, não o objetivo. Pense em quando você deseja alterar todas as divs semelhantes ... você teria que alterá-las para span-11 ou algo semelhante. As classes devem definir o que é. as folhas de estilo devem definir como as coisas olhar
Jonathan Fingland
Como você usaria esse método para especificar mais do que apenas um sinalizador? Costumo concordar com sua postura e não uso atributos personalizados (embora esteja considerando). A vantagem de ter um par de chave / valor parece um pouco mais útil do que simplesmente adicionar outra classe.
TM.
@ Jonathan Fingland: Se o Compass for usado, você não precisará definir os nomes das classes aqui. Você pode apenas especificá-los no arquivo .sass e sua marcação estará limpa.
Alan Haggai Alavi
@ Jonathan Fingland, o classatributo definitivamente não é reservado apenas para "looks". Outro uso é "processamento de propósito geral por agentes do usuário". Disso fala a especificação: w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup
@ npup: escolha interessante de citações. Como afirmei há um ano, as folhas de estilo definem como essas coisas devem ser (assim como o atributo de estilo, acrescentarei), e o atributo de classe é usado para definir a finalidade do elemento. Ou seja, é especificamente usado para definir o que é, e não a aparência. Eu acho que você pode ter simplesmente lido errado o que eu disse, pois estamos de acordo, tanto quanto posso dizer.
Jonathan Fingland