カスタム属性-そうですか、そうではありませんか?


254

最近、主にJavaScriptコードで使用する追加のデータビットを埋め込むことを目的として、HTMLタグでカスタム属性を使用する人々についてますます読んでいます。

カスタム属性を使用することは良い習慣であるかどうか、そしていくつかの代替案が何であるかについてのフィードバックを収集したいと思っていました。

サーバー側とクライアント側の両方のコードを本当に単純化できるようですが、W3Cにも準拠していません。

WebアプリでカスタムHTML属性を使用する必要がありますか?なぜか、なぜそうでないのか?

カスタム属性が良いと思う人のために:それらを使用するときに心に留めておくべきことは何ですか?

カスタム属性が悪いことだと思う人のために:あなたは同じようなことを達成するためにどのような選択肢を使用しますか?

更新: 私は主に、さまざまな方法の背後にある推論と、ある方法が別の方法よりも優れている理由についての点に関心があります。私たちは皆、同じことを達成するために4〜5つの異なる方法を考え出すことができると思います。(非表示の要素、インラインスクリプト、追加のクラス、IDからの情報の解析など)。

更新2: HTML 5 data-属性機能はここで多くのサポートを持っているようです(そして私は同意する傾向があります、それは確かなオプションのように見えます)。これまでのところ、私はこの提案に対する反論をあまり見ていません。このアプローチの使用について心配する問題/落とし穴はありますか?それとも、単に現在のW3C仕様の「無害な」無効化なのでしょうか。


正直なところ、私の当初のスタンスは、それらはそれほど悪いものではないということです。私は実際に座ってこれを適切にバックアップするために利用可能なすべてのオプションを評価する必要があるように感じます。したがって、長いエッセイを書く必要があります。
Paolo Bergantino、

あなたが唯一のいくつかの反例を必要とするかもしれないことを[s]で行うには:あなたはそれを行うには便利ですか、実装しようとしているもののカスタム属性、そしてなぜそのソリューションより良いとして、カスタム属性のない他のソリューションよりも悪くありません。
ChrisW、2009年

@ChrisW私は特定のアプリケーションからではなく、大部分が興味をそそられるように求めています。
TM。

まあ、クライアント側にデータを取得するためのオプションはたくさんあります:非表示の入力フィールド、非表示の定義リスト、クラス、メタデータプラグイン、すべてのデータマッピングを個別に持つ巨大なJavaScript辞書(オブジェクト)、カスタム属性、データ属性( HTML5)など。私はこれらすべてを調査し、それらの利点と落とし穴を検討し、最後に結論に到達したいと考えています。この投稿により、ようやくこれを書き始めることができました。:) 2010
。– Paolo Bergantino

2
@Paoloあなたは私たちにリンクを与えずにこの質問に答えるエッセイを書いたと言うだけではいけません。クールではありません。
Connell

回答:


253

HTML 5では、で始まるカスタム属性を明示的に許可していますdata。したがって、たとえば、<p data-date-changed="Jan 24 5:23 p.m.">Hello</p>有効です。標準で正式にサポートされているので、これはカスタム属性の最良のオプションだと思います。また、ハックで他の属性をオーバーロードする必要がないため、HTMLをセマンティックに保つことができます。

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


これは良いアプローチです。しかし、IE 6や他の古いブラウザをサポートする必要があるとは思いません。
cllpse 2009年

8
私はそれが古いブラウザで動作することをかなり確信しています。属性はDOMに追加され、そこからアクセスできます。
Ms2ger、2009年

12
HTMLElementでgetAttribute()メソッドを使用するすべてのブラウザで完全に機能します。プラス、HTML5データセットとしてサポートは、あなたが簡単であることを追加することができます成長する。
AJM

1
@チャックはどうやら属性をDOCTYPEに追加できます:rodsdot.com/html/…-それは良いアイデアだとは思いませんが、標準化されているようです。
Michael Stum

2
@Wahnfrieden:w3.org/TR/REC-html40/intro/sgmltut.html#idx-attribute-8は、承認された、標準に準拠した方法です。これはよく説明され、ここで示されています。rodsdot.com / html / 以前に他のユーザーが投稿したとおり。
rdivilbiss 2010年

95

これが私が最近使ってきたテクニックです:

<div id="someelement">

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

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

comment-objectは、親要素(つまり、#someelement)に関連付けられます。

これがパーサーです:http : //pastie.org/511358

特定の要素のデータを取得するには、parseDataその要素への参照を唯一の引数として渡して呼び出します。

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

var data = parseData( myElem );

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

それよりも簡潔にすることができます:

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

アクセス:

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

これを使用する唯一の欠点は<img/>、コメントが要素のデータと見なされるように要素内にある必要があるため、自己終了要素(例:)と一緒に使用できないことです。


編集

この手法の注目すべき利点:

  • 実装が簡単
  • HTML / XHTMLを無効にしない
  • 使いやすく、理解しやすい(基本的なJSON表記)
  • ほとんどの代替品よりも目立たず、意味的にクリーン

これがパーサーコードです(pastie.orgで利用できなくなった場合に備えて、上記のhttp://pastie.org/511358ハイパーリンクからコピーされます)。

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;

    };

})();

2
好奇心から、自己終了タグにはどの方法を使用していますか?私は通常、(クライアント側の検証ルールを支援するために)<input>要素でこのようなものを使用する必要があります。あなたはその状況でどのような代替案をとりますか?
TM。

2
私はおそらく、同様の手法を使用します。コメントデータを「parentNode」に関連付ける代わりに、コメントの「previousSibling」に関連付けることができます...次に、<input />の直後にコメントを付けると、作業:<input /> <!-{data:123}->
James

7
誰かがこれをjqueryプラグインにする必要があります
SeanDowney 09/09/23

10
コメントは何も壊すことなく変更/削除できる必要があります。それがポイントです。したがって、マークアップやコードに重要なものをコメントに入れることは悪い考えです。将来の開発者は、それらをコメントであると簡単に考え、削除することができます。「data-」で始まるカスタム属性という本当の解決策はすでにあります。この方法は使用しないでください。
MGOwen 2016

6
@MGOwenのステートメントを強化しましょう。機能を追加するためにコメントを使用しないでください。特にHTMLで。ミニファイアを使用していませんか?コードを壊さずにコメントを削除することはできません。これは、実際のコメントを追加できなくなることも意味します。
オリビクター

15

ページのスキーマを指定すると、任意の属性を作成できます。

例えば:

これを追加

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

Facebook(タグも)

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

10

カスタム属性の使用を回避する最も簡単な方法は、既存の属性を使用することです。

意味のある適切なクラス名を使用してください。
たとえば、のような何かをtype='book'し、type='cd'書籍やCDを表現するために、。クラスは何かが何を表すのに非常に優れているIS

例えば class='book'

私は過去にカスタム属性を使用しましたが、正直なところ、意味的に意味のある方法で既存の属性を利用する場合、それらを実際に使用する必要はありません。

より具体的な例として、さまざまな種類の店舗へのリンクを提供するサイトがあるとします。以下を使用できます。

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

CSSスタイリングは次のようなクラスを使用できます。

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

上記の例では、両方がストアへのリンクであり(サイト上の他の無関係なリンクとは対照的)、1つはcdストアで、もう1つは本屋です。


4
良い点ですが、公平に言うと、「タイプ」は特定のタグでのみ有効であり、それが有効な属性である場合、有効な値のリストも持つため、実際にはw3cに準拠していません。
TM。

1
私のポイントは、これにはtypeタグを使用すべきではないということです。したがって、もしそうなら...それからあなたは...それをより明確にするために編集します
ジョナサン・フィンランド09年

私は「クラス」属性にフレーバーを付けて、いくつかのタイプに「修飾子-」を追加する傾向があります。レイアウトのみに関連するdivの場合、そのクラスは「layout-xxx」にするか、本やストアなどの重要な部分を囲む内部divの場合は、コンテンツブックまたはコンテンツストアを作成します。次に、JavaScriptで、探しているものに基づいて、タグにそれらを付加する関数を使用します。整理整頓に役立ちますが、ある程度の規律と事前整理が必要です。
Ape-in​​ago

2
@ジョナサンダブルクラスの事は「値」が知られていない場合を除いて素晴らしい働きをします。たとえば、それが何らかの整数IDである場合、考えられるすべてのケースに対して非常にうまく選択することはできません。その後、クラス属性を手動で解析する必要がありますが、これは確実に機能しますが、コードではそれほど明確ではなく、場合によっては非常に遅くなる可能性があります(解析する候補要素が多数ある場合)。
TM。

2
残念なことに、2つのクラスのcssセレクターを同時に書き込む(.abで空白がないことに注意)と、IEでは機能しません。ただし、Firefoxやその他のブラウザでは機能します。それでも、クラスを使用することは、マークアップにセマンティックな意味を追加するための優れた方法です
knittl

6

データをdomに埋め込み、jQueryのメタデータを使用します。

すべての優れたプラグインは、メタデータプラグインをサポートしています(タグごとのオプションを許可)。

また、無限に複雑なデータ/データ構造だけでなく、キーと値のペアも使用できます。

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

または

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

または

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

次に、次のようなデータを取得します。

var data = $('li.someclass').metadata();
if ( data.some && data.some == 'random' )
alert('It Worked!');

22
カスタム属性を指定するW3C承認の方法がある場合にクラス属性を破壊することは、おそらく反対票を投じた理由です。
rdivilbiss 2010年

2
クラス属性の破損は、プラグインを使用する方法の1つにすぎません。それが唯一の方法ではありません。
antony.trupe 2014年

1
反対票が投じられたもう1つの理由は、プラグインがまったく必要ないプラグインを提案していることです。
meandre

4

何も壊したり名前空間を拡張したりせずに既存のXHTML機能を使用しても問題はないようです。小さな例を見てみましょう:

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

追加の属性なしでsome_contentに追加情報を追加するにはどうすればよいですか?次のような別のタグを追加するのはどうですか?

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

これは、適切に定義されたID /拡張子「_extended」を介して、階層内の位置によって関係を維持します。私はこのアプローチをjQueryと一緒に使用することが多く、実際にはAjaxのような手法を使用していません。


2
このようにネストされたタグを追加する際の問題は、非常に扱いにくく醜いサーバーサイドコード(JSP / ASP / DTLなど)
TM

3

いや。代わりに次のようなものを試してください:

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

1
それで、動的ページのためにあなたのドキュメント全体にたくさんの追加のスクリプトタグを書くことを好むのですか?クライアント側で情報を追加するときに手動のJavaScript割り当てを使用しますが、この問題は主にサーバーで何をレンダリングするかに関するものです。また、jQuery.data()はメソッドよりもはるかに優れています。
TM。

上記の回答は、機能を実証するための、フレームワークに依存しない、動作が不安定な例です。その要旨を簡単に拡張して、コードをかなり簡潔にすることができます。例:<div id = "foo" /> <div id = "bar" /> <div id = "baz" /> <script type = "text / javascript"> xtrnlFnc({foo: 'w00 h00'、bar : 'etc.'、baz:3.14159}); </ script> jQueryを使用している場合(元の質問で言及していなかった場合)、必ず、データメソッドを使用してください。それが目的です。そうでない場合、アーキテクチャレイヤー間でデータを渡すことは、インラインスクリプトタグの完全に有効な使用法です。
Anon、

これは明らかに明白で有効なオプションです。私の意見では、カスタム属性を使用しない他の多くの選択肢よりもコードが雑然としているだけです。明確にするために、私は戦闘的または失礼なことをしようとしているのではなく、なぜこの方法を好むのかという理由のいくつかを説明しようとしているだけです。あなたは代替案を提供しましたが、それは本当に問題が何であるかではありません。
TM。

1
私はこのアプローチがブラウザーを壊すことに問題はないと思います。MicrosoftはASP.NETページで推奨されるメカニズムであるため、この正確なメカニズムを使用します。(サーバー側でRegisterExpandoAttributeを呼び出すことにより)。質問はサーバーではなくクライアントに焦点を当てているようですが、サーバー側ではこれらすべてのアプローチを抽象化できます(そうする必要がありますか?)。
エイドリアン

3
このアプローチの利点:-有効なマークアップが生成されます(古いブラウザー/仕様でも)。-データの目的(JSによって使用される)を明確にします。-他の機能(コメントなど)を巧みに利用せずに、要素にまとまりがあります。-特別な解析は必要ありません。サーバー側の観点からは、RPCのようなものと考えることができます。
蒸し器

2

XHTMLを出力しているので、カスタム属性を使用していません。サードパーティのソフトウェアでデータを機械可読にしたいからです(ただし、必要に応じてXHTMLスキーマを拡張することもできます)。

カスタム属性の代替として、ほとんどの場合、idおよびクラス属性(たとえば、他の回答で言及されている)で十分です。

また、これを考慮してください:

  • 追加データを人間が読み取れるだけでなく、機械も読み取れるようにする場合は、カスタム属性としてではなく、(可視)HTMLタグとテキストを使用してエンコードする必要があります。

  • それは人間が読めるする必要がない場合は、おそらくそれを使用して符号化することができる不可視の HTMLタグとテキストを。

一部の人々は例外を作ります:それらは実行時にクライアント側でJavaScriptによってDOMに追加されるカスタム属性を許可します。彼らはこれで大丈夫だと考えています。カスタム属性は実行時にDOMにのみ追加されるため、HTMLにはカスタム属性が含まれていません。


1

HTMLのサブセットを理解するWebベースのエディターを作成しました-非常に厳密なサブセット(メールクライアントによってほぼ普遍的に理解されます)。<td width="@INSWIDTH_42@">データベースのようなものを表現する必要がありますが、それをDOMで表現することはできません。そうしないと、エディターが実行されるブラウザーが異常動作します(または、カスタム属性よりも異常動作する可能性が高くなります)。 。ドラッグアンドドロップが必要だったので、jqueryの場合と同様に、DOMに純粋に配置すること.data()はできませんでした(余分なデータが適切にコピーされませんでした)。に乗るには、おそらく追加のデータも必要になるでしょう.html()。最後<td width="1234" rs-width="@INSWIDTH_42@">に、編集プロセス中に使用することに決め、それからすべてをPOSTするときにwidth、正規表現の検索と破棄を削除して実行しs/rs-width=/width=/gます。

最初、これのほとんどを書いている人はこの問題の検証ナチであり、私たちのカスタム属性を回避するためにあらゆることを試みましたが、結局のところ、すべての要件に対して他に何も機能していないようでした。カスタム属性が電子メールに表示されないことを彼が理解したときに役立ちました。で追加データをエンコードするclassことを検討しましたが、それは2つの悪のうちの大きい方だと判断しました。

個人的には、物事をきれいにしてバリデーターを渡すことを好みますが、会社の従業員として、私の主な責任は会社の目的を前進させること(できるだけ早くお金を稼ぐこと)であり、技術的な純度。ツールは私たちのために働くはずです。彼らのためではありません。


1

私は人々がそれに反対しているのを知っています、しかし私はこれのための超短い解決策を思いつきました。「mine」などのカスタム属性を使用する場合は、たとえば次のようにします。

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

次に、このコードを実行して、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;
});

0

仕様:JavaScriptを使用して、プロパティ「DecimalSeparator」と「ThousandsSeparator」に従って、テキストを数値として動的に自動フォーマットするASP.NET TextBoxコントロールを作成します。


これらのプロパティをコントロールからJavaScriptに転送する1つの方法は、コントロールにカスタムプロパティをレンダリングさせることです。

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

カスタムプロパティはJavaScriptから簡単にアクセスできます。また、カスタムプロパティを持つ要素を使用するページは検証されませんが、そのページのレンダリングには影響しません。


私は唯一の私はJavaScriptで使用するHTML要素に文字列と整数のような単純なタイプを関連付けたい場合は、このアプローチを使用しています。HTML要素を識別しやすくしたい場合は、classプロパティとidプロパティを使用します。


0

複雑なWebアプリの場合、カスタム属性をあちこちにドロップします。

もっと一般向けのページでは、 "rel"属性を使用してすべてのデータをJSONにダンプし、それをMooToolsまたはjQueryでデコードします。

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

私は最近「準備」するためだけにHTML 5データ属性に固執しようとしていますが、まだ自然には来ていません。


-1

たとえば、<ai = "" ...などのカスタムフィールドを常に使用しています。次に、jqueryでiを参照します。無効なhtml、はい。はい、うまくいきます。


何かがここで欠けているように見えます。ここでタグは完成しましたか?
Stuart Siegler

どうすればこれを理解できますか?回答を完了してください。
Rahul Raj

-2

私の考えでは、カスタム属性は検証されないので使用しないでください。その代わりに、次のような単一の要素に対して多くのクラスを定義できます。

<div class='class1 class2 class3'>
    Lorem ipsum
</div>

10
個人的にはこれはひどい例だと思います。クラス名は目的ではなく、外観を定義します。同様のdivをすべて変更する場合を考えてみてください。すべてをdiv-11などに変更する必要があります。クラスはそれが何であるかを定義する必要があります。スタイルシートは、これらの外観を定義する必要があります
Jonathan Fingland

このメソッドを使用して、フラグ以外のものをどのように指定しますか?私はあなたのスタンスに同意する傾向があり、カスタム属性は使用していません(ただし、検討中です)。キーと値のペアを持つことの利点は、単に別のクラスを追加するよりもかなり便利に思えます。
TM。

@Jonathan Fingland:Compassを使用する場合、ここでクラス名を設定する必要はありません。.sassファイルで指定するだけで、マークアップがクリーンになります。
アランハガイAlavi

@Jonathan Fingland、このclass属性は「見た目」のみに予約されることはありません。もう1つの用途は、「ユーザーエージェントによる汎用処理」です。このうち、仕様を説明します:w3.org/TR/REC-html40/struct/global.html#h-7.5.2
npup

@npup:引用符の興味深い選択。1年以上前に述べたように、スタイルシートはそれらの外観を定義し(style属性と同様に追加します)、class属性を使用して要素の目的を定義します。つまり、それが何であるかを定義するために具体的に使用されており、見た目ではありません。私の知る限りでは、私たちが同意しているので、私が言ったことを単に誤って読んだのではないかと思います。
ジョナサンフィンランド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.