Atributos personalizados: ¿sí o no?

254

Recientemente he estado leyendo más y más acerca de personas que usan atributos personalizados en sus etiquetas HTML, principalmente con el propósito de incrustar algunos bits adicionales de datos para usar en el código JavaScript.

Esperaba reunir algunos comentarios sobre si usar o no atributos personalizados es una buena práctica, y también cuáles son algunas alternativas.

Parece que lo que realmente puede simplificar tanto del lado del servidor y el código del lado del cliente, sino que también no es compatible con W3C.

¿Deberíamos estar utilizando atributos HTML personalizados en nuestras aplicaciones web? ¿Por qué o por qué no?

Para aquellos que piensan que los atributos personalizados son algo bueno: ¿cuáles son algunas cosas a tener en cuenta al usarlos?

Para aquellos que piensan que los atributos personalizados son malos: ¿qué alternativas utilizan para lograr algo similar?

Actualización: estoy principalmente interesado en el razonamiento detrás de los diversos métodos, así como en los puntos de por qué un método es mejor que otro. Creo que todos podemos encontrar 4-5 formas diferentes de lograr lo mismo. (elementos ocultos, scripts en línea, clases adicionales, información de análisis de ID, etc.).

Actualización 2: Parece que la data-característica de atributo HTML 5 tiene mucho soporte aquí (y tiendo a estar de acuerdo, parece una opción sólida). Hasta ahora no he visto mucho en el camino de las refutaciones para esta sugerencia. ¿Hay problemas / dificultades para preocuparse por usar este enfoque? ¿O es simplemente una invalidación 'inofensiva' de las especificaciones actuales del W3C?

TM.
fuente
Honestamente, mi postura inicial es que son no tan malo, que puede ser bastante polémica con los puristas. Sin embargo, siento que realmente necesito sentarme y evaluar todas las opciones disponibles para respaldar esto correctamente, por lo tanto, es necesario escribir el ensayo largo.
Paolo Bergantino
Para hacerlo, es posible que solo necesite algunos contraejemplos [s]: de lo que está tratando de implementar, cómo es conveniente hacerlo con atributos personalizados y por qué esa solución es mejor y no peor que otras soluciones sin atributos personalizados.
ChrisW
@ChrisW Estoy preguntando principalmente por interés, no por alguna aplicación específica.
TM.
Bueno, hay muchas opciones para llevar los datos al lado del cliente: campos de entrada ocultos, listas de definiciones ocultas, clases, complementos de metadatos, tener un gran diccionario (objeto) de JavaScript con toda la asignación de datos por separado, atributos personalizados, atributos de datos ( HTML5), etc. Quiero explorar todo esto, considerar sus méritos, sus trampas y finalmente llegar a una conclusión. Esta publicación finalmente me hizo comenzar a escribir esto. :) Debe hacerse antes de 2010.
Paolo Bergantino
2
@Paolo, no puedes decir que escribiste un ensayo respondiendo esta pregunta sin darnos el enlace. No es genial
Connell

Respuestas:

253

HTML 5 permite explícitamente atributos personalizados que comienzan con data. Entonces, por ejemplo, <p data-date-changed="Jan 24 5:23 p.m.">Hello</p>es válido. Dado que es oficialmente compatible con un estándar, creo que esta es la mejor opción para los atributos personalizados. Y no requiere que sobrecargues otros atributos con hacks, por lo que tu HTML puede permanecer semántico.

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

Arrojar
fuente
Este es un buen enfoque ... Pero dudo que funcione si tiene que soportar IE 6 y otros navegadores antiguos.
cllpse
8
Estoy bastante seguro de que funciona con navegadores antiguos; los atributos se agregan al DOM, donde puede acceder a ellos.
Ms2ger
12
Funciona perfectamente bien con todos los navegadores que utilizan el método getAttribute () en un elemento HTMLElement. Además, como HTML5 apoyo conjunto de datos crece puede agregar fácilmente que en.
AJM
1
@Chuck aparentemente puedes agregar Atributos al DOCTYPE: rodsdot.com/html/… , aunque no creo que sea una buena idea, pero parece estandarizado.
Michael Stum
2
@Wahnfrieden: w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8, que es el método aprobado y que cumple con los estándares. Lo cual está bien descrito y demostrado aquí: rodsdot.com/html/… Como lo publicaron previamente otros.
rdivilbiss
95

Aquí hay una técnica que he estado usando recientemente:

<div id="someelement">

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

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

El objeto de comentario se vincula con el elemento padre (es decir, #someelement).

Aquí está el analizador: http://pastie.org/511358

Para obtener los datos de cualquier elemento en particular, simplemente llame parseDatacon una referencia a ese elemento pasado como único argumento:

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

var data = parseData( myElem );

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

Puede ser más sucinto que eso:

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

Acceder a él:

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

La única desventaja de usar esto es que no se puede usar con elementos de cierre automático (p <img/>. Ej. ), Ya que los comentarios deben estar dentro del elemento para ser considerados como datos de ese elemento.


EDITAR :

Beneficios notables de esta técnica:

  • Fácil de implementar
  • Hace no invalida HTML / XHTML
  • Fácil de usar / entender (notación JSON básica)
  • Discreto y semánticamente más limpio que la mayoría de las alternativas.

Aquí está el código del analizador (copiado del hipervínculo http://pastie.org/511358 anterior, en caso de que alguna vez no esté disponible en 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
fuente
2
Por curiosidad, ¿qué método utilizas para las etiquetas de cierre automático? Generalmente necesito usar algo como esto en los elementos <input> (para ayudar en las reglas de validación del lado del cliente). ¿Qué alternativa tomas en esa situación?
TM.
2
Probablemente usaría una técnica similar, en lugar de los datos del comentario vinculados al "parentNode", podría vincularse con el "anteriorSibling" del comentario ... Entonces podría tener el comentario inmediatamente después de <input /> y sería trabajo: <input /> <! - {data: 123} ->
James
77
alguien debe hacer de este un plugin de jQuery
SeanDowney
10
Los comentarios deben poder modificarse / eliminarse sin romper nada. Ese es todo el punto. Por lo tanto, es una mala idea poner algo importante para el marcado o el código en los comentarios. Los futuros desarrolladores podrían fácilmente pensar que son comentarios y eliminarlos. Ya tenemos una solución real a esta pregunta: atributos personalizados con el prefijo "datos-". Este enfoque nunca debe usarse.
MGOwen
66
Permítanme reforzar la declaración de @MGOwen: no use comentarios para agregar funcionalidad. Especialmente en el HTML. ¿No estás usando minificadores? No podrá eliminar comentarios sin romper su código. Esto también significa que ya no puede agregar comentarios reales.
Olivictor
15

Puede crear cualquier atributo si especifica un esquema para su página.

Por ejemplo:

Agrega esto

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

Facebook (incluso etiquetas)

<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
fuente
10

La forma más fácil de evitar el uso de atributos personalizados es usar los atributos existentes.

usar nombres de clase significativos y relevantes.
Por ejemplo, haga algo como: type='book'y type='cd', para representar libros y cds. Las clases son mucho mejores para representar lo que ES algo .

p.ej class='book'

He usado atributos personalizados en el pasado, pero honestamente, realmente no hay necesidad de usarlos si utiliza los atributos existentes de una manera semánticamente significativa.

Para dar un ejemplo más concreto, supongamos que tiene un sitio que ofrece enlaces a diferentes tipos de tiendas. Puedes usar lo siguiente:

<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>

El estilo CSS podría usar clases como:

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

En el ejemplo anterior, vemos que ambos son enlaces a tiendas (a diferencia de otros enlaces no relacionados en el sitio) y uno es una tienda de CD, y el otro es una librería.

Jonathan Fingland
fuente
44
Buen punto, pero para ser justos, "tipo" solo es válido en ciertas etiquetas, y cuando ES un atributo válido, también tiene una lista de valores válidos, por lo que aún no cumple con w3c.
TM.
1
mi punto era que NO deberías usar la etiqueta de tipo para esto. de ahí el Si se va ... entonces debería ... Voy a editar para hacer más clara que
Jonathan Fingland
Tiendo a hacer mis atributos de "clase" con sabores añadiendo algunos de ellos con algún tipo de "calificador". para los divs relacionados solo con el diseño, tendría que su clase sea "layout-xxx", o para los divs internos que rodean una parte importante, como un libro o una tienda, tendría un libro de contenido o una tienda de contenido . luego, en mi JavaScript, tengo una función que antepone esas cosas en la etiqueta en función de lo que estoy buscando. me ayuda a mantener las cosas limpias y organizadas, pero requiere un cierto nivel de disciplina y organización previa.
Ape-inago
2
@Jonathan lo de clase doble funciona muy bien, excepto en los casos en que no se conocen los "valores". Por ejemplo, si se trata de algún tipo de identificación de entero, no podemos seleccionar muy bien para cada caso posible. Luego, debemos analizar el atributo de clase manualmente, lo que definitivamente es viable, pero no tan claro en el código, y en algunos casos, podría ser muy lento (si hay muchos elementos candidatos para analizar).
TM.
2
lamentablemente, escribir selectores css para dos clases al mismo tiempo (.ab nota que falta el espacio en blanco) no funciona en IE. Sin embargo, funciona en Firefox y otros navegadores. Sin embargo, el uso de clases es una gran manera de significado semántico adicional incrustar a su margen de beneficio
knittl
6

Incruste los datos en el dom y use metadatos para jQuery .

Todos los complementos buenos son compatibles con el complemento de metadatos (permitiendo las opciones por etiqueta).

También permite estructuras de datos / datos infinitamente complejas, así como pares clave-valor.

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

O

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

O

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

Luego obtenga los datos de esta manera:

var data = $('li.someclass').metadata();
if ( data.some && data.some == 'random' )
alert('It Worked!');
antony.trupe
fuente
22
Corromper el atributo de clase cuando hay una forma aprobada por el W3C de especificar atributos personalizados es probablemente la razón por la que fue rechazado.
rdivilbiss
2
corromper el atributo de clase es solo una de las formas de usar el complemento; No es la única manera.
antony.trupe
1
Otra razón por la que fue rechazado es sugerir un complemento donde no se necesita ningún complemento.
meandre
4

No veo ningún problema en usar las funciones XHTML existentes sin romper nada o extender su espacio de nombres. Echemos un vistazo a un pequeño ejemplo:

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

¿Cómo agregar información adicional a some_content sin atributos adicionales? ¿Qué hay de agregar otra etiqueta como la siguiente?

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

Mantiene la relación a través de una identificación / extensión bien definida "_extendida" de su elección y por su posición en la jerarquía. A menudo uso este enfoque junto con jQuery y sin usar técnicas similares a Ajax.

Merkuro
fuente
2
El problema con agregar etiquetas anidadas como esta es que tiende a crear código MUY engorroso y feo en el servidor (JSP / ASP / DTL, etc.)
TM.
3

No. Pruebe algo como esto en su lugar:

<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>
Luego
fuente
1
¿Entonces prefiere escribir muchas etiquetas de script adicionales en todo el documento para páginas dinámicas? Usaría las asignaciones manuales de JavaScript cuando se agregue la información en el lado del cliente, pero este problema se trata principalmente de qué representar en el servidor. Además, jQuery.data () es mucho mejor que su método.
TM.
La respuesta anterior es un ejemplo independiente y estructurado para demostrar la funcionalidad. Podrías expandirlo fácilmente para que el código sea bastante conciso. Por ejemplo, <div id = "foo" /> <div id = "bar" /> <div id = "baz" /> <script type = "text / javascript"> xtrnlFnc ({foo: 'w00 h00', bar : 'etc.', baz: 3.14159}); </script> Si está utilizando jQuery (no es que lo haya mencionado en su pregunta original), utilice el método de datos, para eso sirve. De lo contrario, pasar datos entre capas arquitectónicas es un uso perfectamente válido de las etiquetas de script en línea.
Anon
Definitivamente es una opción obvia y válida. En mi opinión, simplemente llena el código mucho más que muchas otras alternativas que no usan atributos personalizados. Y para ser claros, no estoy tratando de ser combativo o grosero, solo estoy tratando de convencer algunos de tus razonamientos de por qué prefieres este método. Usted ha proporcionado una alternativa, pero esa no es realmente la cuestión.
TM.
1
No creo que haya un problema con este enfoque que rompe los navegadores. Microsoft usa este mecanismo exacto, ya que es el mecanismo preferido en las páginas ASP.NET. (llamando a RegisterExpandoAttribute en el lado del servidor). La pregunta parece centrada en el cliente y no en el servidor, pero en el lado del servidor todos estos enfoques podrían ser (¿deberían ser?) Abstraídos.
Adrian
3
Los pros de este enfoque: - Produce un marcado válido (incluso bajo los antiguos navegadores / especificaciones). - Deja clara la intención de los datos (para ser consumidos por JS). --Es coherente con el elemento sin hacer un uso inteligente de otras características (como comentarios). - No requiere un análisis especial. Desde la perspectiva del lado del servidor, puede pensar que es como un RPC.
steamer25
2

No estoy usando atributos personalizados, porque estoy produciendo XHTML, porque quiero que los datos sean legibles por máquina por software de terceros (aunque, podría extender el esquema XHTML si quisiera).

Como alternativa a los atributos personalizados, en su mayoría encuentro suficientes los atributos de identificación y clase (por ejemplo, como se menciona en otras respuestas).

Además, considere esto:

  • Si los datos adicionales deben ser legibles por humanos y por máquina, entonces deben codificarse utilizando etiquetas y texto HTML (visibles) en lugar de atributos personalizados.

  • Si no necesita ser legible por humanos, entonces tal vez pueda codificarse usando etiquetas y texto HTML invisibles .

Algunas personas hacen una excepción: permiten atributos personalizados, agregados al DOM por Javascript en el lado del cliente en tiempo de ejecución. Consideran que esto está bien: como los atributos personalizados solo se agregan al DOM en tiempo de ejecución, el HTML no contiene atributos personalizados.

ChrisW
fuente
1

Hemos creado un editor basado en la web que comprende un subconjunto de HTML, un subconjunto muy estricto (que los clientes de correo entienden casi universalmente). Necesitamos expresar cosas como <td width="@INSWIDTH_42@">en la base de datos, pero no podemos tener eso en el DOM, de lo contrario, el navegador donde se ejecuta el editor se asusta (o es más probable que se asuste de lo que es probable que se asuste por los atributos personalizados) . Queríamos arrastrar y soltar, por lo que ponerlo solo en el DOM estaba fuera, al igual que jquery .data()(los datos adicionales no se copiaron correctamente). Probablemente también necesitábamos los datos adicionales para el viaje .html(). Al final, decidimos usar <td width="1234" rs-width="@INSWIDTH_42@">durante el proceso de edición, y luego, cuando PUBLICAMOS todo, eliminamos widthy hacemos una búsqueda y destrucción de expresiones regulares s/rs-width=/width=/g.

Al principio, el tipo que escribió la mayor parte de esto fue el nazi de validación sobre este tema e intentó todo para evitar nuestro atributo personalizado, pero al final accedió cuando nada más parecía funcionar para TODOS nuestros requisitos. Le ayudó cuando se dio cuenta de que el atributo personalizado nunca aparecería en un correo electrónico . Consideramos codificar nuestros datos adicionales class, pero decidimos que sería el mayor de los dos males.

Personalmente, prefiero tener las cosas limpias y aprobar validadores, etc., pero como empleado de la compañía debo recordar que mi responsabilidad principal es avanzar en la causa de la compañía (ganar la mayor cantidad de dinero lo más rápido posible), no la de mi deseo egoísta de pureza técnica Las herramientas deberían funcionar para nosotros; No nosotros por ellos.

Bernd Jendrissek
fuente
1

Sé que la gente está en contra, pero se me ocurrió una solución súper corta para esto. Si desea utilizar un atributo personalizado como "mío", por ejemplo:

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

Luego puede ejecutar este código para recuperar un objeto tal como lo hace 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
fuente
0

Especificación: Cree un control ASP.NET TextBox que formatee automáticamente su texto como un número, de acuerdo con las propiedades "DecimalSeparator" y "ThousandsSeparator", utilizando JavaScript.


Una forma de transferir estas propiedades del control a JavaScript es hacer que el control muestre propiedades personalizadas:

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

Las propiedades personalizadas son fácilmente accesibles por JavaScript. Y aunque una página que usa elementos con propiedades personalizadas no se validará , la representación de esa página no se verá afectada.


Yo sólo se utiliza este enfoque cuando quiero asociar tipos simples como cadenas y números enteros a los elementos HTML para su uso con JavaScript. Si quiero que los elementos HTML sean más fáciles de identificar, haré uso de las propiedades de clase e id .

cllpse
fuente
0

Para aplicaciones web complejas, suelto atributos personalizados en todo el lugar.

Para páginas más públicas, uso el atributo "rel" y vuelco todos mis datos allí en JSON y luego lo decodifico con MooTools o jQuery:

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

Estoy tratando de mantener el atributo de datos HTML 5 últimamente solo para "prepararme", pero aún no ha llegado de forma natural.

Ryan Florence
fuente
-1

Uso campos personalizados todo el tiempo, por ejemplo <ai = "" .... Luego, hago referencia a i con jquery. HTML no válido, sí. Funciona bien, si.

Mario
fuente
Algo parece que falta aquí. ¿Tu etiqueta estaba completa aquí?
Stuart Siegler
¿Cómo puede alguien comprender esto? Por favor complete su respuesta.
Rahul Raj
-2

Los atributos personalizados, en mi humilde opinión, no deben usarse ya que no validan. Alternativa a eso, puede definir muchas clases para un solo elemento como:

<div class='class1 class2 class3'>
    Lorem ipsum
</div>
Alan Haggai Alavi
fuente
10
Personalmente, creo que este es un ejemplo terrible. Sus nombres de clase definen cómo se ve, no su propósito. Piensa en cuándo quieres cambiar todos los divs similares ... tendrías que ir y cambiarlos a span-11 o similares. Las clases deben definir lo que ES. las hojas de estilo deben definir cómo se ven las cosas
Jonathan Fingland
¿Cómo usarías este método para especificar más que solo una bandera? Tiendo a estar de acuerdo con tu postura, y no uso atributos personalizados (aunque lo estoy considerando). La ventaja de tener un par clave / valor parece bastante más útil que simplemente agregar otra clase.
TM.
@ Jonathan Fingland: Si se usa Brújula, no necesita establecer los nombres de clase aquí. Simplemente puede especificarlos en el archivo .sass y su marcado estará limpio.
Alan Haggai Alavi
@ Jonathan Fingland, el classatributo definitivamente no está reservado solo para "miradas". Otro uso es el "procesamiento de propósito general por parte de agentes de usuario". De esto habla la especificación: w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup
@npup: interesante elección de citas. Como dije hace más de un año, las hojas de estilo definen cómo deberían verse esas cosas (al igual que el atributo de estilo, agregaré), y el atributo de clase se usa para definir el propósito del elemento. Es decir, se usa específicamente para definir lo que ES, y no cómo se ve. Creo que es posible que haya leído mal lo que dije, ya que estamos de acuerdo en lo que puedo decir.
Jonathan Fingland