JavaScriptからのCSS疑似クラスルールの設定


125

JavaScriptから擬似クラスセレクター(:link、:hoverなど)のCSSルールを変更する方法を探しています。

CSSコードの類似:a:hover { color: red }JSで。

他に答えは見つかりませんでした。これがブラウザでサポートされていないことを誰かが知っていれば、それも役立つ結果になります。

回答:


192

(セレクターがないため)インラインstyle = "..."属性に疑似クラスを設定できないのと同じ方法で、特定の要素だけで疑似クラスのスタイルを設定することはできません。

たとえば、ルールを追加して、スタイルシートを変更することでそれを行うことができます。

#elid:hover { background: red; }

影響を与えたい各要素に一意のIDがあり、それを選択できると仮定します。

理論的には、必要なドキュメントはhttp://www.w3.org/TR/DOM-Level-2-Style/Overview.htmlですこれは、次のような構文を使用して(既存の埋め込みまたはリンクされたスタイルシートがある場合)できることを意味します。

document.styleSheets[0].insertRule('#elid:hover { background-color: red; }', 0);
document.styleSheets[0].cssRules[0].style.backgroundColor= 'red';

もちろん、IEには独自の構文が必要です。

document.styleSheets[0].addRule('#elid:hover', 'background-color: red', 0);
document.styleSheets[0].rules[0].style.backgroundColor= 'red';

古いブラウザーとマイナーブラウザーはどちらの構文もサポートしない可能性があります。動的なスタイルシートの変更は、正しく行うのが非常に煩わしく、めったに必要とされず、歴史的に面倒なので、めったに行われません。


32
なぜこれが答えとして選ばれなかったのですか?
SZH


2
Firefox:「エラー:操作は安全ではありません。」
8128 2012

@flutefluteは、別のドメインからCSSファイルを操作しようとしている場合、その操作は安全ではないと見なされます(これは一種の同一生成元ポリシーのことだと思います)。恥!シンプルな機能は、同一生成元ポリシーに準拠を確認する: function sameOrigin(url) { var loc = window.location, a = document.createElement('a'); a.href = url; return a.hostname === loc.hostname && a.port === loc.port && a.protocol === loc.protocol; }
WickyNilliams

3
特定の要素にスタイルを適用するためだけにスタイルシートを操作すると、スタイルシートが変更されるたびにブラウザーがドキュメント全体をリフローするため、お勧めできません。stubbornella.org/content/2009/03/27/...
ヨハネス・エワルド

29

JSでスタイルシートを操作するための有効なユースケースがあると思うので、このための小さなライブラリを一緒に投げました。理由:

  • 計算または取得する必要のあるスタイルの設定-たとえば、Cookieからのユーザーの優先フォントサイズの設定。
  • 特にUIウィジェット/プラグイン開発者向けの、(美的ではない)動作スタイルの設定。タブ、カルーセルなどは、単に機能するためにいくつかの基本的なCSSを必要とすることがよくあります- コア機能のスタイルシートを要求すべきではありません。
  • CSSルールは現在および将来のすべての要素に適用され、Firebug /開発者ツールで表示するときにHTMLが乱雑にならないため、インラインスタイルよりも優れています。

17

クロスブラウザのものに対処する関数:

addCssRule = function(/* string */ selector, /* string */ rule) {
  if (document.styleSheets) {
    if (!document.styleSheets.length) {
      var head = document.getElementsByTagName('head')[0];
      head.appendChild(bc.createEl('style'));
    }

    var i = document.styleSheets.length-1;
    var ss = document.styleSheets[i];

    var l=0;
    if (ss.cssRules) {
      l = ss.cssRules.length;
    } else if (ss.rules) {
      // IE
      l = ss.rules.length;
    }

    if (ss.insertRule) {
      ss.insertRule(selector + ' {' + rule + '}', l);
    } else if (ss.addRule) {
      // IE
      ss.addRule(selector, rule, l);
    }
  }
};

7

テンプレート文字列にcssを配置するだけです。

const cssTemplateString = `.foo:[psuedoSelector]{prop: value}`;

次に、スタイル要素を作成し、文字列をスタイルタグに配置してドキュメントに添付します。

const styleTag = document.createElement("style");
styleTag.innerHTML = cssTemplateString;
document.head.insertAdjacentElement('beforeend', styleTag);

残りは、特異性が対応します。その後、スタイルタグを動的に削除および追加できます。これは、ライブラリの単純な代替手段であり、DOMのスタイルシート配列をいじくります。ハッピーコーディング!


insertAdjacentElement主要なブラウザー(Chrome、Firefox、Edge)で2つの引数が必要です。最初の引数は、参照要素に対する相対的な位置を確立します(ここを参照)。これは最近の変更ですか?(答えに 'beforeend'を追加しました)。
折りたたみ式2018

6

私のトリックは、属性セレクターを使用することです。JavaScriptを使用すると、属性を簡単に設定できます。

CSS

.class{ /*normal css... */}
.class[special]:after{ content: 'what you want'}

JavaScript

  function setSpecial(id){ document.getElementById(id).setAttribute('special', '1'); }

html

<element id='x' onclick="setSpecial(this.id)"> ...  

4
このソリューションはjQueryを使用します。質問者が純粋なJavascriptを要求したときに、これと同じくらい単純なものに対してjQueryのサイズの依存関係を導入することは悪いことです。
トムアシュワース

最近ではすべてのWebサイトでjqueryが使用されていますが、純粋なjavascriptを使用するように変更します。
Sergio Abreu 2013年

1
そして、このメソッドはどのようにして、背景色などの.class [special]:after疑似要素のCSS属性を変更するのでしょうか。
andreszs 14

5

別の選択肢があります。擬似クラスを直接操作する代わりに、「ホバー」クラスや「訪問済み」クラスなど、同じものをモデル化する実際のクラスを作成します。通常の「。」でクラスをスタイルします。構文を使用すると、JavaScriptを使用して、適切なイベントが発生したときに要素からクラスを追加または削除できます。


2
:beforeおよび:after擬似クラスでは機能しません。
jbyrd 2014年

また、AJAX経由で取得した値で背景画像を変更することはできません。
andreszs 14

1
@ jbyrd、:before:afterはクラスではなく、疑似要素です。
Roy Ling

@royling-はい、修正してくれてありがとう!コメントを編集できないようです。
jbyrd 2015年

4

JavaScriptを使用して疑似クラスルールを直接設定する代わりに、異なるCSSファイルで異なるルールを設定し、JavaScriptを使用して1つのスタイルシートをオフに切り替え、別のスタイルシートをオンに切り替えることができます。メソッドは、A List Apart(詳細についてはqv。)で説明されています。

CSSファイルを次のように設定します。

<link rel="stylesheet" href="always_on.css">
<link rel="stylesheet" title="usual" href="preferred.css"> <!-- on by default -->
<link rel="alternate stylesheet" title="strange" href="alternate.css"> <!-- off by default -->

そして、JavaScriptを使用してそれらを切り替えます:

function setActiveStyleSheet(title) {
   var i, a, main;
   for(i=0; (a = document.getElementsByTagName("link")<i>); i++) {
     if(a.getAttribute("rel").indexOf("style") != -1
        && a.getAttribute("title")) {
       a.disabled = true;
       if(a.getAttribute("title") == title) a.disabled = false;
     }
   }
}

クラスをAJAXリクエストで取得した値に動的に変更する必要がある場合はどうなりますか?現在、CSSファイルを作成できません...
andreszs

2

すでに述べたように、これはブラウザがサポートするものではありません。

スタイルを動的に思いついていない場合(つまり、データベースなどからスタイルを取得している場合)は、ページの本文にクラスを追加することで、この問題を回避できるはずです。

CSSは次のようになります。

a:hover { background: red; }
.theme1 a:hover { background: blue; }

そして、これを変更するJavaScriptは次のようになります。

// Look up some good add/remove className code if you want to do this
// This is really simplified

document.body.className += " theme1";  

好奇心から、element.classList.add十分にサポートされていませんか?私は人々がしているのを見続けelement.className +=ます。
Joel Cornett 2014年

2
classListはより新しい機能であり、ごく最近まで(caniuse.com/classlistを参照)までは十分なサポートがあったように見えません
Nathaniel Reinhart


-1

jqueryでは、ホバー疑似クラスを簡単に設定できます。

$("p").hover(function(){
$(this).css("background-color", "yellow");
}, function(){
$(this).css("background-color", "pink");
});

-1

ここに2つの関数を含むソリューションがあります:addCSSclassはドキュメントに新しいcssクラスを追加し、toggleClassはそれをオンにします

この例では、divにカスタムスクロールバーを追加しています

// If newState is provided add/remove theClass accordingly, otherwise toggle theClass
function toggleClass(elem, theClass, newState) {
  var matchRegExp = new RegExp('(?:^|\\s)' + theClass + '(?!\\S)', 'g');
  var add = (arguments.length > 2 ? newState : (elem.className.match(matchRegExp) === null));

  elem.className = elem.className.replace(matchRegExp, ''); // clear all
  if (add) elem.className += ' ' + theClass;
}

function addCSSclass(rules) {
  var style = document.createElement("style");
  style.appendChild(document.createTextNode("")); // WebKit hack :(
  document.head.appendChild(style);
  var sheet = style.sheet;

  rules.forEach((rule, index) => {
    try {
      if ("insertRule" in sheet) {
        sheet.insertRule(rule.selector + "{" + rule.rule + "}", index);
      } else if ("addRule" in sheet) {
        sheet.addRule(rule.selector, rule.rule, index);
      }
    } catch (e) {
      // firefox can break here          
    }
    
  })
}

let div = document.getElementById('mydiv');
addCSSclass([{
    selector: '.narrowScrollbar::-webkit-scrollbar',
    rule: 'width: 5px'
  },
  {
    selector: '.narrowScrollbar::-webkit-scrollbar-thumb',
    rule: 'background-color:#808080;border-radius:100px'
  }
]);
toggleClass(div, 'narrowScrollbar', true);
<div id="mydiv" style="height:300px;width:300px;border:solid;overflow-y:scroll">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a eros metus. Nunc dui felis, accumsan nec aliquam quis, fringilla quis tellus. Nulla cursus mauris nibh, at faucibus justo tincidunt eget. Sed sodales eget erat consectetur consectetur. Vivamus
  a diam volutpat, ullamcorper justo eu, dignissim ante. Aenean turpis tortor, fringilla quis efficitur eleifend, iaculis id quam. Quisque non turpis in lacus finibus auctor. Morbi ullamcorper felis ut nulla venenatis fringilla. Praesent imperdiet velit
  nec sodales sodales. Etiam eget dui sollicitudin, tempus tortor non, porta nibh. Quisque eu efficitur velit. Nulla facilisi. Sed varius a erat ac volutpat. Sed accumsan maximus feugiat. Mauris id malesuada dui. Lorem ipsum dolor sit amet, consectetur
  adipiscing elit. Sed a eros metus. Nunc dui felis, accumsan nec aliquam quis, fringilla quis tellus. Nulla cursus mauris nibh, at faucibus justo tincidunt eget. Sed sodales eget erat consectetur consectetur. Vivamus a diam volutpat, ullamcorper justo
  eu, dignissim ante. Aenean turpis tortor, fringilla quis efficitur eleifend, iaculis id quam. Quisque non turpis in lacus finibus auctor. Morbi ullamcorper felis ut nulla venenatis fringilla. Praesent imperdiet velit nec sodales sodales. Etiam eget
  dui sollicitudin, tempus tortor non, porta nibh. Quisque eu efficitur velit. Nulla facilisi. Sed varius a erat ac volutpat. Sed accumsan maximus feugiat. Mauris id malesuada dui.
</div>


-2

REACTを使用する場合、ラジウムと呼ばれるものがあります。ここでとても便利です:

  • インタラクティブなスタイルが指定されている場合は、プロップにハンドラーを追加します(例::hoverのonMouseEnter、必要に応じて既存のハンドラーをラップ)

  • いずれかのハンドラーがトリガーされた場合(ホバーなど)、RadiumはsetStateを呼び出して、コンポーネントの状態オブジェクトのRadium固有のフィールドを更新します

  • 再レンダリング時に、要素のキーまたは参照をラジウム固有の状態で検索することにより、適用されるすべてのインタラクティブスタイル、たとえば:hoverを解決します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.