web-dev-qa-db-fra.com

Modification des valeurs de propriété de classe CSS à la volée avec JavaScript/jQuery

J'ai rencontré une situation unique pour laquelle je n'ai pas encore trouvé de solution: attribuer dynamiquement une valeur à un style CSS. Je sais comment utiliser jQuery pour attribuer la largeur, la hauteur, etc. à un élément, mais ce que j'essaie de faire, c'est de changer la valeur définie dans la feuille de style afin que la valeur créée dynamiquement puisse être affectée à plusieurs éléments. 

Ce que je construis est un diaporama d'images qui occupent la totalité de la fenêtre, recalculant la largeur, la hauteur et les propriétés de gauche de l'image lors du redimensionnement de manière à ce que l'image soit toujours centrée et favorise la largeur par rapport à la hauteur, sauf si la fenêtre est plus haute qu'elle ne l'est large (redimensionner ne recharge pas la page, déclenche simplement une fonction pour redimensionner l'image). 

J'ai réussi à le faire fonctionner sur une image et j'essaie maintenant de déterminer le meilleur moyen d'attribuer ces valeurs de propriété à toutes les images du diaporama sans avoir à spécifier ces trois éléments individuellement pour chaque image. 

Ma question:

Les valeurs des propriétés d'une classe peuvent-elles être modifiées à la volée? Je suis sûr que la réponse est là-bas, je n'utilise probablement pas la terminologie correcte dans mes recherches. J'espère que j'ai bien décrit le problème. TIA.

50
JPN

Contrairement à certaines des réponses fournies ici, éditer la feuille de style elle-même avec Javascript est non seulement possible, mais plus performant. Si vous faites simplement $('.myclass').css('color: red'), vous obtiendrez une boucle sur chaque élément correspondant au sélecteur et définissez individuellement l'attribut style. C'est vraiment inefficace et si vous avez des centaines d'éléments, cela va poser des problèmes.

Changer les classes sur les éléments est une meilleure idée, mais vous rencontrez toujours le même problème, vous modifiez un attribut sur N éléments, ce qui peut être un nombre élevé. Une meilleure solution consisterait peut-être à modifier la classe d’un seul élément parent ou d’un petit nombre de parents, puis à cliquer sur les éléments cibles à l’aide de "Cascade" dans css. Cela sert dans la plupart des situations, mais pas toutes.

Parfois, vous devez modifier le CSS d'un grand nombre d'éléments en un élément dynamique, ou vous n'avez aucun moyen de le faire en touchant un petit nombre de parents. Modifier la feuille de style elle-même ou en ajouter une nouvelle pour remplacer le fichier CSS existant est un moyen extrêmement efficace de modifier l'affichage des éléments. Vous n'interagissez avec le DOM que d'un seul endroit et le navigateur peut gérer le déploiement de ces modifications de manière très efficace.

jss est une bibliothèque qui facilite la modification directe de la feuille de style à partir de javascript.

28
user748221

Démo , IE démo

Vous pouvez utiliser la fonction suivante:

function setStyle(cssText) {
    var sheet = document.createElement('style');
    sheet.type = 'text/css';
    /* Optional */ window.customSheet = sheet;
    (document.head || document.getElementsByTagName('head')[0]).appendChild(sheet);
    return (setStyle = function(cssText, node) {
        if(!node || node.parentNode !== sheet)
            return sheet.appendChild(document.createTextNode(cssText));
        node.nodeValue = cssText;
        return node;
    })(cssText);
};

Caractéristiques:

  • La fonction est écrite en vanilla-js, elle a donc de meilleures performances que les alternatives jQuery
  • Une feuille de style est créée après le premier appel à setStyle. Par conséquent, si vous ne l'appelez pas, elle ne créera aucune feuille de style.
  • La même feuille de style est réutilisée pour les appels suivants de setStyle
  • La fonction renvoie une référence au nœud associé au groupe de CSS que vous avez ajouté. Si vous appelez à nouveau la fonction avec ce nœud comme second argument, l'ancienne CSS sera remplacée par la nouvelle.

Exemple

var myCSS = setStyle('*{ color:red; }');
setStyle('*{ color:blue; }', myCSS); // Replaces the previous CSS with this one

Support du navigateur

Au moins, cela fonctionne sur IE9, FF3, Chrome 1, Safari 4, Opera 10.5.

Il existe également une version IE qui fonctionne aussi bien sur les navigateurs modernes que sur les anciennes versions de IE! (Fonctionne sur IE8 et IE7, mais peut bloquer IE6).

21
Oriol

Bonne question. Beaucoup de réponses ici avaient une solution contredisant directement ce que vous demandiez

"Je sais comment utiliser jQuery pour attribuer la largeur, la hauteur, etc. à un élément, mais ce que j'essaie de faire, c'est de modifier la valeur définie dans la feuille de style afin que la valeur créée dynamiquement puisse être affectée à plusieurs éléments.
"

jQuery .css styles elements inline : cela ne change pas la règle CSS physique! Si vous voulez faire cela, je suggérerais d'utiliser une solution JavaScript Vanilla:

document.styleSheets[0].cssRules[0].cssText = "\
     #myID {
         myRule: myValue;
         myOtherRule: myOtherValue;
     }";

De cette façon, vous définissez la règle css de feuille de style, sans ajouter de style en ligne.

J'espère que cela t'aides!

18
Jace Cotton

Comme @benvie l'a dit, il est plus efficace de modifier une feuille de style plutôt que d'utiliser jQuery.css (qui parcourt tous les éléments de l'ensemble). Il est également important de ne pas ajouter de nouveau style à la tête chaque fois que la fonction est appelée car cela créerait une fuite de mémoire et des milliers de règles CSS devant être appliquées individuellement par le navigateur. Je ferais quelque chose comme ça:

//Add the stylesheet once and store a cached jQuery object
var $style = $("<style type='text/css'>").appendTo('head'); 

function onResize() {
    var css = "\
        .someClass {\
            left:   "+leftVal+";\
            width:  "+widthVal+";\
            height: "+heightVal+";\
        }";

    $style.html(css);
}

Cette solution modifiera vos styles en modifiant le DOM une seule fois par redimensionnement. Notez que pour une compression et une minimisation efficaces de js, vous ne voulez probablement pas imprimer en jolis les fichiers css, mais je l’ai fait pour plus de clarté.

8
Brian Peacock

Utilisez jquery pour ajouter un remplacement de style dans le <head>:

$('<style>.someClass {color: red;} input::-webkit-outer-spin-button: {display: none;}</style>')
.appendTo('head'); 
5
user2041268

J'ai une solution pour changer une valeur dans une classe CSS spécifique. Mais cela ne fonctionne que si vous gardez votre CSS dans la balise. Si vous conservez simplement un lien vers votre CSS à partir de fichiers externes ex. 

<style src='script.js'></style>

cette solution ne fonctionnera pas.

Si votre css ressemble à ceci par exemple: 

<style id='style'>
.foo {
height:50px;
}
</style>

Vous pouvez modifier une valeur de la balise à l'aide de JS/jQuery.

J'ai écrit une fonction, peut-être que ce n'est pas la meilleure mais ça marche. Vous pouvez l'améliorer si vous voulez.

function replaceClassProp(cl,prop,val){

if(!cl || !prop || !val){console.error('Wrong function arguments');return false;}


// Select style tag value

var tag = '#style';

    var style = $(tag).text();
    var str = style;

// Find the class you want to change
    var n = str.indexOf('.'+cl);
    str = str.substr(n,str.length);
    n = str.indexOf('}');
    str = str.substr(0,n+1);

    var before = str;

// Find specific property

    n = str.indexOf(prop);
    str = str.substr(n,str.length);
    n = str.indexOf(';');
    str = str.substr(0,n+1);

// Replace the property with values you selected

    var after = before.replace(str,prop+':'+val+';');
    style=style.replace(before,after);

// Submit changes

    $(tag).text(style);

}

Puis changez simplement la variable de balise en votre id de balise de style et exécutez:

replaceClassProp('foo','height','50px');

La différence entre this et $ ('. Foo'). Css ('height', '50px'); est que lorsque vous le faites avec la méthode CSS de jQuery, tous les éléments ayant la classe .foo auront un style visible = 'height: 50px' dans DOM. Si vous le faites à ma façon, les éléments ne sont pas touchés et la seule chose que vous verrez est class = 'foo'

Avantages

  • Effacer DOM
  • Vous pouvez modifier la propriété que vous voulez sans remplacer le style entier

Désavantages

  • Seulement CSS interne
  • Vous devez trouver la balise de style spécifique que vous souhaitez modifier

J'espère que ça aide quand même.

4
wopolow

Vous ne pouvez pas modifier les membres d'une classe CSS à la volée. Cependant, vous pouvez introduire une nouvelle balise <style> sur la page avec votre nouvelle implémentation de classe css, puis changer de classe. Exemple:

Sample.css

.someClass { border: 1px solid black; font-size: 20px; }

Vous voulez changer complètement cette classe, vous créez donc un nouvel élément de style:

<style>
   .someClassReplacement { border: 1px solid white; font-size: 14px; }       
</style>

Vous effectuez ensuite un remplacement simple via jQuery:

$('.someClass').removeClass('someClass').addClass('someClassReplacement');
3
Tejs
function changeStyle(findSelector, newRules) {
    // Change original css style declaration.   
    for ( s in document.styleSheets ) {
        var CssRulesStyle = document.styleSheets[s].cssRules;
        for ( x in CssRulesStyle ) {
            if ( CssRulesStyle[x].selectorText == findSelector) {
                for ( cssprop in newRules ) {
                    CssRulesStyle[x].style[cssprop] = newRules[cssprop];
                }

                return true;
            }
        }
    }

    return false;
}

changeStyle('#exact .myStyle .declaration', {'width':'200px', 'height':'400px', 'color':'#F00'});
2
Cycne

Pourquoi ne pas simplement utiliser un sélecteur .class pour modifier les propriétés de chaque objet de cette classe?

c'est à dire:

$('.myclass').css('color: red;');

2
JJ.

D'accord .. eu le même problème et résolu, mais la solution peut ne pas être pour tout le monde.

Si vous connaissez les index de la feuille de style et de la règle que vous souhaitez supprimer, essayez quelque chose comme document.styleSheets[1].deleteRule(0);.

Depuis le début, j'ai eu mon fichier main.css (index 0). Ensuite, j'ai créé un nouveau fichier, js_edit.css (index 1), qui ne contenait qu'une règle avec les propriétés que je souhaitais supprimer une fois le chargement de la page terminé (après de nombreuses autres fonctions JS également).

Maintenant, puisque js_edit.css se charge après main.css, vous pouvez simplement insérer/supprimer des règles dans js_edit.css à votre guise et elles remplaceront celles de main.css..

var x = document.styleSheets[1];
x.insertRule("p { font-size: 2rem; }", x.cssRules.length);

x.cssRules.length renvoie le nombre de règles de la deuxième feuille de style (index 1), insérant ainsi la nouvelle règle à la fin.

Je suis sûr que vous pouvez utiliser un tas de boucles for pour rechercher la règle/propriété que vous souhaitez modifier, puis réécrire toute la règle dans la même feuille, mais j'ai trouvé cette méthode plus simple pour mes besoins.

http://www.quirksmode.org/dom/w3c_css.html m'a beaucoup aidé.

1
LGT

YUI 2 et 3 ont une feuille de style de module qui vous permettra de faire exactement cela (éditez des feuilles de style à la volée avec javascript). http://yuilibrary.com/yui/docs/stylesheet/ . Donc je pense que c'est possible. Ce n'est pas la même chose que $ (". Some"). Css ({...}), mais change vraiment/ajoute/supprime la définition des styles de la feuille de style, comme le demandait l'utilisateur.

1
cancerbero

Vous devriez vraiment repenser votre approche de cette question. Utiliser un sélecteur bien conçu et attacher la classe peut être une solution plus élégante à cette approche. Autant que je sache, vous ne pouvez pas modifier les CSS externes.

1
Kevin Bowersox

Cette solution modifie Cycne pour utiliser la syntaxe ES6 et quitter la boucle plus tôt pour les feuilles de style externes. Cette solution ne modifie pas les feuilles de style externes

function changeStyle(findSelector, newDeclarations) {
    // Change original css style declaration.
    document.styleSheets.forEach((sheet) => {
      if (sheet.href) return;
      const cssRulesList = sheet.cssRules;
      cssRulesList.forEach((styleRule) => {
        if (styleRule.selectorText === findSelector) {
          Object.keys(newDeclarations).forEach((cssProp) => {
            styleRule.style[cssProp] = newDeclarations[cssProp];
          });
        }
      });
    });
  }

  const styleDeclarations = {
    'width': '200px',
    'height': '400px',
    'color': '#F00'
  };
  changeStyle('.paintBox', styleDeclarations);

Vous devez également avoir au moins une balise de style dans votre section d'en-tête HTML, par exemple

<style> .paintBox {background-color: white;}</style>
0
Tovieye Ozi

La discussion risque d’être tardive, mais j’avais besoin de quelque chose comme ce dont on parle ici, mais je n’ai rien trouvé qui corresponde vraiment à ce que je voulais, et c’est fait facilement. Ce dont j'avais besoin était de masquer et d'afficher de nombreux éléments sans visiter explicitement chaque élément individuellement pour les mettre à jour d'une manière qui modifiait le style d'affichage masqué ou masqué. Alors je suis venu avec ce qui suit:

<style>
  /* The bulk of the css rules should go here or in an external css file */
  /* None of these rules will be changed, but may be overridden */
  .aclass { display: inline-block; width: 50px; height: 30px; }
</style>
<style id="style">
  /* Only the rules to be changed should go in this style */
  .bclass { display: inline-block; }
</style>
<script>
  //
  // This is a helper function that returns the named style as an object.
  // This could also be done in other ways.
  // 
  function setStyle() { return document.getElementById( 'style' ); }
</script>
<div id="d1" class="aclass" style="background-color: green;">
  Hi
</div>
<!-- The element to be shown and hidden --> 
<div id="d2" class="aclass bclass" style="background-color: yellow;">
  there
</div>
<div id="d3" class="aclass" style="background-color: lightblue;">
  sailor
</div>
<hr />
<!-- These buttons demonstrate hiding and showing the d3 dive element -->
<button onclick="setStyle().innerHTML = '.bclass { display: none; }';">
  Hide
</button>&nbsp;&nbsp;
<button onclick="setStyle().innerHTML = '.bclass { display: inline-block; }';">
  Show
</button>

En basculant la règle bclass dans la feuille de style incorporée et nommée, qui vient après les autres feuilles de style pertinentes, dans ce cas une avec la règle aclass, je pourrais mettre à jour la règle display css en un seul endroit et la remplacer par la règle aclass , qui avait aussi sa propre règle d'affichage.

La beauté de cette technique réside dans le fait qu’elle est si simple, qu’une seule ligne qui effectue le travail proprement dit ne nécessite aucune bibliothèque, telle que JQuery ou des plug-ins, et le vrai travail de mise à jour de tous les endroits où le changement a été effectué. s'applique est effectuée par la fonctionnalité de base css du navigateur, pas en JavaScript. En outre, il fonctionne dans IE 9 et les versions ultérieures, Chrome, Safari, Opera et tous les autres navigateurs que Microsoft Edge pouvait émuler, pour les appareils de bureau et les tablettes/téléphones.

0
Howard Brown