web-dev-qa-db-fra.com

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

Cela fait déjà un moment que je réfléchis à ce qui suit: je veux maintenant connaître votre opinion, vos solutions possibles, etc.

Je recherche un plugin ou une technique permettant de changer la couleur d'un texte ou de basculer 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 partie couverte de l'arrière-plan est plutôt sombre, faites le texte en blanc ou changez les icônes.

De plus, il serait bon que le script remarque si le parent n'a pas de couleur d'arrière-plan ou d'image-définie, puis continue à rechercher le plus proche (de l'élément parent à son élément parent ..).

Que pensez-vous savoir de cette idée? Y a-t-il déjà quelque chose de similaire? exemples de script?

Cheers, J.

98
James Cazzetta

Ressources intéressantes pour cela:

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

var rgb = [255, 0, 0];

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

function setContrast() {
  // randomly update
  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
  var o = Math.round(((parseInt(rgb[0]) * 299) +
                      (parseInt(rgb[1]) * 587) +
                      (parseInt(rgb[2]) * 114)) / 1000);
  var fore = (o > 125) ? 'black' : 'white';
  var back = 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
  $('#bg').css('color', fore); 
  $('#bg').css('background-color', back);
  

}
#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>
153
Alex Ball

Cet article sur 24 façons de Calcul du contraste des couleurs pourrait vous intéresser. Ignorez le premier ensemble de fonctions car elles sont incorrectes, mais la formule YIQ vous aidera à déterminer si vous souhaitez 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 à partir de l'article pour déterminer une couleur de premier 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';
}
46
cyang

Question interessante. Ma pensée immédiate était d’inverser la couleur de l’arrière-plan en tant que texte. Cela implique simplement d'analyser l'arrière-plan et d'inverser sa valeur RVB.

Quelque chose comme ceci: 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+')');
15
jeremyharris

mix-blend-mode fait le tour:

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): Après, un tutoriel de Nice expliquant tous les différents types de modes/implémentations: https://css-tricks.com/css-techniques-and-effects-for-knockout-text/ =

5
James Cazzetta

J'ai trouvé le script BackgroundCheck très utile.

Il détecte la luminosité globale 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 ou background--dark), en fonction de la luminosité de l'arrière-plan.

Il peut être appliqué aux éléments immobiles et en mouvement.

( Source )

4
cptstarling

Si vous utilisez ES6, convertissez hex en RVB puis pouvez utiliser ceci:

const hexToRgb = hex => {
    // turn hex val to RGB
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
    return result
        ? {
              r: parseInt(result[1], 16),
              g: parseInt(result[2], 16),
              b: parseInt(result[3], 16)
          }
        : null
}

// calc to work out if it will match on black or white better
const setContrast = rgb =>
    (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000 > 125 ? 'black' : 'white'

const getCorrectColor = setContrast(hexToRgb(#ffffff))
3
Luke Robertson

Voici ma tentative:

(function ($) {
    $.fn.contrastingText = function () {
        var el = this,
            transparent;
        transparent = function (c) {
            var m = c.match(/[0-9]+/g);
            if (m !== null) {
                return !!m[3];
            }
            else return false;
        };
        while (transparent(el.css('background-color'))) {
            el = el.parent();
        }
        parts = el.css('background-color').match(/[0-9]+/g);
        this.lightBackground = !!Math.round(
            (
                parseInt(parts[0], 10) + // red
                parseInt(parts[1], 10) + // green
                parseInt(parts[2], 10) // blue
            ) / 765 // 255 * 3, so that we avg, then normalise to 1
        );
        if (this.lightBackground) {
            this.css('color', 'black');
        } else {
            this.css('color', 'white');
        }
        return this;
    };
}(jQuery));

Puis l'utiliser:

var t = $('#my-el');
t.contrastingText();

Cela va tout de suite rendre le texte noir ou blanc selon le cas. Pour faire les icônes:

if (t.lightBackground) {
    iconSuffix = 'black';
} else {
    iconSuffix = 'white';
}

Ensuite, chaque icône pourrait ressembler à 'save' + iconSuffix + '.jpg'.

Notez que cela ne fonctionnera pas si un conteneur déborde de son parent (par exemple, si la hauteur CSS est 0 et que le débordement n'est pas masqué). Pour que cela fonctionne, ce serait beaucoup plus complexe.

3
Nathan MacInnes