162 votes

Changer la couleur du texte en fonction de la luminosité de la zone d'arrière-plan couverte ?

Je suis à la recherche d'un plugin ou d'une technique qui change la couleur d'un texte ou bascule entre des images/icônes prédéfinies en fonction de la luminosité moyenne des pixels couverts de l'image ou de la couleur d'arrière-plan de son parent.

Si la zone couverte par son fond est plutôt sombre, rendez le texte blanc ou changez les icônes.

De plus, ce serait génial si le script remarquait si le parent n'a pas de couleur de fond ou d'image définie et continuait ensuite à chercher la plus proche (de l'élément parent à son élément parent ).

Que pensez-vous, que savez-vous de cette idée ? Existe-t-il déjà quelque chose de similaire ? Des exemples ?

1 votes

Juste une pensée plutôt qu'une réponse. Il y a peut-être un moyen de définir vos couleurs en utilisant HSL puis en regardant la valeur de luminosité. Si cette valeur est supérieure à une certaine valeur, appliquez une règle css.

1 votes

On pourrait concevoir d'analyser la couleur d'arrière-plan d'un élément en valeurs R, G, B (et alpha facultatif), en remontant l'arbre DOM si le canal alpha est défini sur zéro. Cependant, essayer de déterminer la couleur d'une image d'arrière-plan est une toute autre affaire.

0 votes

232voto

Alex Ball Points 2013

Des ressources intéressantes à cet égard :

Voici l'algorithme du W3C (avec La démo de JSFiddle aussi ):

const rgb = [255, 0, 0];

// Randomly change to showcase updates
setInterval(setContrast, 1000);

function setContrast() {
  // Randomly update colours
  rgb[0] = Math.round(Math.random() * 255);
  rgb[1] = Math.round(Math.random() * 255);
  rgb[2] = Math.round(Math.random() * 255);

  // http://www.w3.org/TR/AERT#color-contrast
  const brightness = Math.round(((parseInt(rgb[0]) * 299) +
                      (parseInt(rgb[1]) * 587) +
                      (parseInt(rgb[2]) * 114)) / 1000);
  const textColour = (brightness > 125) ? 'black' : 'white';
  const backgroundColour = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
  $('#bg').css('color', textColour); 
  $('#bg').css('background-color', backgroundColour);
}

#bg {
  width: 200px;
  height: 50px;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="bg">Text Example</div>

1 votes

Peut être raccourci à ce qui suit, à condition de lui passer un objet ::: : const setContrast = rgb => (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000 > 125 ? 'black' : 'white'

3 votes

Avez-vous vraiment besoin de jquery juste pour changer le css ?

0 votes

@bluejayke non, il y a d'autres moyens ;-)

111voto

cyang Points 1651

Cet article sur les 24 façons de Calcul du contraste des couleurs pourrait vous intéresser. Ignorez la première série de fonctions car elles sont fausses, mais la formule YIQ vous aidera à déterminer si vous devez utiliser une couleur de premier plan claire ou foncée.

Une fois que vous avez obtenu la couleur d'arrière-plan de l'élément (ou de l'ancêtre), vous pouvez utiliser cette fonction de l'article pour déterminer une couleur d'avant-plan appropriée :

function getContrastYIQ(hexcolor){
    hexcolor = hexcolor.replace("#", "");
    var r = parseInt(hexcolor.substr(0,2),16);
    var g = parseInt(hexcolor.substr(2,2),16);
    var b = parseInt(hexcolor.substr(4,2),16);
    var yiq = ((r*299)+(g*587)+(b*114))/1000;
    return (yiq >= 128) ? 'black' : 'white';
}

0 votes

Merci, c'est vraiment utile Cela dépend de la couleur de fond définie Mais savez-vous comment obtenir la couleur moyenne d'une image en parcourant chaque pixel (comme dans une boucle) ?

4 votes

Dans es6, vous pouvez le faire avec : const getContrastYIQ = hc => { const [r, g, b] = [0, 2, 4].map( p => parseInt( hc.substr( p, 2 ), 16 ) ); return ((r * 299) + (g * 587) + (b * 114)) / 1000 >= 128; }

0 votes

J'ai pris cette fonction et je l'ai un peu étendue pour que vous puissiez renvoyer deux couleurs personnalisées, plutôt que toujours noir et blanc. Notez que si les couleurs sont très proches l'une de l'autre, vous pouvez toujours avoir des problèmes de contraste, mais c'est une bonne alternative au retour des couleurs absolues. jsfiddle.net/1905occv/1

23voto

James Cazzetta Points 669

mix-blend-mode fait l'affaire :

header {
  overflow: hidden;
  height: 100vh;
  background: url(https://www.w3schools.com/html/pic_mountain.jpg) 50%/cover;
}

h2 {
  color: white;
  font: 900 35vmin/50vh arial;
  text-align: center;
  mix-blend-mode: difference;
  filter: drop-shadow(0.05em 0.05em orange);
}

<header>
  <h2 contentEditable role='textbox' aria-multiline='true' >Edit me here</h2>
</header>

Ajout (mars 2018) : Suite, un beau tutoriel expliquant tous les différents types de modes/implémentations : https://css-tricks.com/css-techniques-and-effects-for-knockout-text/

1 votes

Surpris que cela ne soit pas plus haut - cela a parfaitement fonctionné pour moi et c'est super simple à mettre en œuvre.

16voto

jeremyharris Points 5924

Question intéressante. J'ai tout de suite pensé à inverser la couleur du fond en fonction du texte. Pour cela, il suffit d'analyser l'arrière-plan et d'inverser sa valeur RVB.

Quelque chose comme ça : http://jsfiddle.net/2VTnZ/2/

var rgb = $('#test').css('backgroundColor');
var colors = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
var brightness = 1;

var r = colors[1];
var g = colors[2];
var b = colors[3];

var ir = Math.floor((255-r)*brightness);
var ig = Math.floor((255-g)*brightness);
var ib = Math.floor((255-b)*brightness);

$('#test').css('color', 'rgb('+ir+','+ig+','+ib+')');

0 votes

Vous voudrez probablement désaturer votre couleur "inversée" en faisant la moyenne des valeurs inversées R, V, B et en les rendant égales entre elles. Cependant, cette solution obtient sa couleur de base à partir d'une chaîne de caractères, et non à partir de la propriété CSS de l'élément. Pour être fiable, la solution devrait obtenir dynamiquement les couleurs d'arrière-plan, qui renvoient généralement des valeurs rgb() ou rgba(), mais qui peuvent différer selon le navigateur.

0 votes

Oui. Pour faciliter l'analyse, j'ai simplement utilisé une valeur hexagonale. J'ai mis à jour le truc pour inclure la récupération de la couleur de l'élément dans le CSS. J'ai mis à jour le truc et inclus une sorte de contrôle de la luminosité (je ne connais rien aux mathématiques des couleurs, donc ce n'est probablement pas vraiment la luminosité).

0 votes

@jeremyharris Ce code est très utile, mais pour étendre les possibilités, savez-vous comment obtenir la couleur moyenne d'une image en parcourant chaque pixel (comme dans une boucle) ? Ainsi, au lieu de récupérer la couleur de fond via CSS, nous pourrions obtenir la couleur moyenne de l'image de fond.

6voto

cptstarling Points 711

J'ai trouvé le Vérification des antécédents script pour être très utile.

Il détecte la luminosité générale de l'arrière-plan (qu'il s'agisse d'une image de fond ou d'une couleur), et applique une classe à l'élément de texte attribué ( background--light o background--dark ), qui dépend de la luminosité de l'arrière-plan.

Elle peut être appliquée à des éléments fixes ou en mouvement.

( Source : )

0 votes

Cela fonctionne-t-il pour les couleurs d'arrière-plan ? J'ai lu rapidement le script, et je ne vois pas qu'il utilise la couleur de fond pour vérifier la luminosité. Seulement les images.

1 votes

Bonjour Jørgen, je pense que le script colourBrightness script peut répondre à votre besoin : github.com/jamiebrittain/colourBrightness.js

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X