カバーされた背景領域の明るさに基づいてテキストの色を変更しますか?


114

もうしばらく前から考えていたので、今から皆さんの意見や考えられる解決策などを知りたいです。

テキストの色を変更したり、親のbackground-imageまたは-colorの覆われたピクセルの平均輝度に応じて、定義済みの画像/アイコンを切り替えたりするプラグインまたはテクニックを探しています。

背景の覆われた領域がかなり暗い場合は、テキストを白にするか、アイコンを切り替えます。

さらに、親がbackground-colorまたは-imageを定義していないかどうかをスクリプトが認識し、最も近いもの(親要素からその親要素まで)を検索し続けるとすばらしいでしょう。

この考えについてどう思いますか?すでに似たようなものはありますか?スクリプト例?

乾杯、J。


1
答えではなく単なる考え。HSLを使用して色を設定し、明度の値を確認する方法があるかもしれません。その値が特定の値を超える場合は、CSSルールを適用します。
スコットブラウン

1
おそらく、要素の背景色をR、G、B(およびオプションのアルファ)値に解析し、アルファチャネルがゼロに設定されている場合はDOMツリーを処理することができます。ただし、背景画像の色を決定することは、まったく別の問題です。
jackwanders


@Pascalかなり似ていて、良い入力ですが、それは私の質問に対する正確な答えではありません。
James Cazzetta 2013年

回答:


175

このための興味深いリソース:

これがW3Cアルゴリズムです(JSFiddleデモも使用)。

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>


あなたが正しいフェリックス!私は今離れていますが、戻ってきたら答えを更新します
Alex Ball

1
オブジェクトに:::: const setContrast = rgb =>(rgb.r * 299 + rgb.g * 587 + rgb.b * 114)/ 1000> 125を渡すと、次のように短縮できますか?「黒」:「白」
ルークロバートソン

CSSを変更するためだけにjqueryが必要ですか?
bluejayke

@bluejaykeいいえ、他の方法があります;-)
Alex Ball

62

カラーコントラストの計算に関する24の方法に関するこの記事は、興味を引くかもしれません。関数の最初のセットは間違っているため無視しますが、YIQ式は明るい前景色または暗い前景色を使用するかどうかを判断するのに役立ちます。

要素(または祖先)の背景色を取得したら、記事のこの関数を使用して、適切な前景色を決定できます。

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';
}

おかげで、これは本当に便利です。これは、設定されたbackground-colorに依存します。しかし、(ループのように)各ピクセルを実行して、画像の平均色を取得する方法を知っていますか?
James Cazzetta、2012

4
:ES6ではあなたがこれを行うことができます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; }
Centril

この関数を少し拡張して、常に白黒ではなく、2つのカスタムカラーを返すことができるようにしました。色が2つ接近している場合でもコントラストの問題が発生する可能性がありますが、これは絶対色を返す代わりに良い方法ですjsfiddle.net/1905occv/1
Hanna

1
これはcooです。yiqを160以上に調整するだけで、うまくいきました。
アルトゥーロ

15

興味深い質問です。私が直ぐに思ったのは、テキストの背景の色を反転させることでした。これには、単に背景を解析し、そのRGB値を反転することが含まれます。

このようなもの: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+')');

おそらく、反転されたR、G、Bの値を平均し、それらを互いに等しく設定することによって、「反転された」色の彩度を下げたいでしょう。ただし、このソリューションでは、要素のCSSプロパティからではなく、文字列からベースカラーを取得しています。信頼できるようにするには、ソリューションは背景色を動的に取得する必要があります。これは通常rgb()またはrgba()の値を返しますが、ブラウザーによって異なる場合があります。
ジャックワンダーズ

はい。解析を簡単にするために、16進数の値を使用しました。CSSから要素の色を取得するようにフィドルを更新しました。私はフィドルを更新し、一種の明るさコントロールを含めました(カラー数学については何も知らないので、おそらく真の明るさではありません)。
jeremyharris


2
背景色が#808080!?
Nathan MacInnes、2012

1
@NathanMacInnesそれはまだそれを反転します、それはたまたまスペクトルの真ん中で何かを反転するとそれ自体が生じるということです。このコードは色を反転するだけで、制限があります。
jeremyharris 2012

9

mix-blend-mode トリックを行います:

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>

追加(2018年3月):次に、すべての異なるタイプのモード/実装を説明する素晴らしいチュートリアル:https : //css-tricks.com/css-techniques-and-effects-for-knockout-text/


5

BackgroundCheckスクリプトが非常に役立つことがわかりました。

これは、背景の全体的な明るさ(背景画像または色)を検出し、背景の明るさに応じて、割り当てられたテキスト要素(background--lightまたはbackground--dark)にクラスを適用します。

静止した要素や移動する要素に適用できます。

出典


貢献してくれてありがとう!
James Cazzetta

これは背景色で機能しますか?スクリプトをすばやく読みましたが、背景色を利用して明るさを確認できません。画像のみ。
ヨルゲンSKÄRフィッシャー

1
こんにちはヨルゲン、colourBrightnessスクリプトはあなたの目的に役立つかもしれないと思います:github.com/jamiebrittain/colourBrightness.js
cptstarling

5

ES6を使用している場合は、hexをRGBに変換すると、次のように使用できます。

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

4

これが私の試みです:

(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();
        }
        var 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 normalize to 1
        );
        if (this.lightBackground) {
            this.css('color', 'black');
        } else {
            this.css('color', 'white');
        }
        return this;
    };
}(jQuery));

それを使用するには:

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

これはすぐにテキストを黒または白にします。アイコンを実行するには:

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

次に、各アイコンはのようになり'save' + iconSuffix + '.jpg'ます。

これは、コンテナが親をオーバーフローする場所では機能しないことに注意してください(たとえば、CSSの高さが0で、オーバーフローが非表示になっていない場合)。これを機能させるには、かなり複雑になります。


1

答えを組み合わせることで[@ alex-ball、@jeremyharris]私はこれが私にとって最良の方法であることがわかりました:

        $('.elzahaby-bg').each(function () {
            var rgb = $(this).css('backgroundColor');
            var colors = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);

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

            var o = Math.round(((parseInt(r) * 299) + (parseInt(g) * 587) + (parseInt(b) * 114)) /1000);

            if(o > 125) {
                $(this).css('color', 'black');
            }else{
                $(this).css('color', 'white');
            }
        });
*{
    padding: 9px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class='elzahaby-bg' style='background-color:#000'>color is white</div>

<div class='elzahaby-bg' style='background-color:#fff'>color is black</div>
<div class='elzahaby-bg' style='background-color:yellow'>color is black</div>
<div class='elzahaby-bg' style='background-color:red'>color is white</div>

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