Metin rengi, kapsanan arka plan alanının parlaklığına göre değiştirilsin mi?


114

Aşağıdakileri bir süredir düşündüm, bu yüzden şimdi fikirlerinizi, olası çözümlerinizi vb. Bilmek istiyorum.

Bir metnin rengini değiştiren veya önceden tanımlanmış resimler / simgeler arasında, ebeveynin arka plan görüntüsünün veya renginin kapsanan piksellerinin ortalama parlaklığına bağlı olarak geçiş yapan bir eklenti veya teknik arıyorum.

Arka planının kapalı alanı oldukça karanlıksa, metni beyaz yapın veya simgeleri değiştirin.

Ek olarak, komut dosyası, üst öğenin tanımlanmış arka plan rengi veya resmi olmadığını fark ederse ve ardından en yakınını aramaya devam ederse (ana öğeden ana öğesine ..) harika olurdu.

Ne düşünüyorsun, bu fikri biliyor musun? Orada zaten benzer bir şey var mı? script örnekler?

Şerefe, J.


1
Cevaptan ziyade sadece bir düşünce. Renklerinizi HSL kullanarak ayarlamanın ve ardından açıklık değerine bakmanın bir yolu olabilir. Bu değer belirli bir değerin üzerindeyse, bir css kuralı uygulayın.
Scott Brown

1
Alfa kanalı sıfıra ayarlanmışsa, bir elemanın arka plan rengini R, G, B (ve isteğe bağlı alfa) değerlerine ayrıştırabilir ve DOM ağacını çalıştırabilirsiniz. Bununla birlikte, bir arka plan görüntüsünün rengini belirlemeye çalışmak tamamen başka bir konudur.
jackwanders


@Pascal Oldukça benzer ve iyi girdi .. ama sorumun tam cevabı bu değil.
James Cazzetta

Yanıtlar:


176

Bunun için ilginç kaynaklar:

İşte W3C algoritması ( JSFiddle demosu ile de ):

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>


Felix haklısın! şimdi uzaktayım, ama eminim, geri döndüğümde cevabı güncelleyeceğim
Alex Ball

1
Bir nesneyi iletmeniz koşuluyla aşağıdakilere kısaltılabilir :::: const setContrast = rgb => (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000> 125? "siyah": "beyaz"
Luke Robertson

Sadece css'yi değiştirmek için jquery'ye ihtiyacınız var mı?
bluejayke

@bluejayke hayır, başka yollar var ;-)
Alex Ball

63

Renk Kontrastını Hesaplamanın 24 yolu hakkındaki bu makale ilginizi çekebilir. İlk işlev kümesini yok sayın çünkü yanlışlar, ancak YIQ formülü açık veya koyu ön plan rengi kullanıp kullanmayacağınızı belirlemenize yardımcı olacaktır.

Öğenin (veya atanın) arka plan rengini elde ettiğinizde, uygun bir ön plan rengi belirlemek için makaledeki bu işlevi kullanabilirsiniz:

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

Teşekkürler, bu gerçekten yardımcı oluyor .. Bu, ayarlanan arka plan rengine bağlıdır .. Ama bir görüntünün ortalama rengini her pikselden (bir döngüdeki gibi) geçerek nasıl elde edeceğinizi biliyor musunuz?
James Cazzetta

4
Es6'da bunu aşağıdakilerle yapabilirsiniz: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

Bu işlevi aldım ve her zaman siyah beyaz yerine iki özel renk döndürebilmeniz için biraz genişlettim. Renkler birbirine yakın olsa bile, yine de kontrast sorunları yaşayabilirsiniz, ancak bu, mutlak renkleri döndürmek için iyi bir alternatiftir jsfiddle.net/1905occv/1
Hanna

2
bu coo, yiq'i> = 160 olarak ayarlardım, benim için daha iyi çalıştı.
Arturo

15

İlginç soru. Hemen aklıma gelen, arka planın rengini metin olarak tersine çevirmekti. Bu sadece arka planı ayrıştırmayı ve RGB değerini ters çevirmeyi içerir.

Bunun gibi bir şey: 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+')');

Muhtemelen ters çevrilmiş R, G, B değerlerinin ortalamasını alarak ve bunları birbirine eşitleyerek 'ters çevrilmiş' renginizi desatürasyona uğratmak isteyebilirsiniz. Ancak bu çözüm, temel rengini öğenin CSS özelliğinden değil, bir dizeden alıyor. Güvenilir olması için, çözümün dinamik olarak arka plan renklerini elde etmesi gerekir, bu genellikle rgb () veya rgba () değerlerini döndürür, ancak tarayıcıya göre farklılık gösterebilir.
jackwanders

Evet. Ayrıştırma kolaylığı için, sadece bir onaltılık değer kullandım. Keman'ı, öğenin rengini CSS'den almayı içerecek şekilde güncelledim. Keman'ı güncelledim ve bir çeşit parlaklık kontrolü ekledim (Renk matematiği hakkında hiçbir şey bilmiyorum, bu yüzden muhtemelen gerçek parlaklık değil).
jeremyharris


2
Arka plan rengi ne olur #808080!?
Nathan MacInnes

1
@NathanMacInnes hala onu tersine çevirecek, sadece spektrumun tam ortasında bir şeyi tersine çevirmek kendi başına sonuçlanacak. Bu kod, sınırlamaları ile birlikte gelen rengi tersine çevirir.
jeremyharris

9

mix-blend-mode hile yapar:

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>

Ekleme (Mart 2018): Tüm farklı mod / uygulama türlerini açıklayan güzel bir öğretici: https://css-tricks.com/css-techniques-and-effects-for-knockout-text/


5

BackgroundCheck komut dosyasını çok faydalı buldum .

Arka planın genel parlaklığını (bir arka plan görüntüsü veya bir renk olabilir) algılar ve arka planın parlaklığına bağlı olarak, atanan metin öğesine ( background--lightveya background--dark) bir sınıf uygular .

Hareketsiz ve hareketli elemanlara uygulanabilir.

( Kaynak )


Katkı için teşekkürler!
James Cazzetta

Bu arka plan renkleri için çalışıyor mu? Komut dosyasını hızlıca okudum ve parlaklığı kontrol etmek için arka plan rengini kullandığını göremiyorum. Yalnızca görüntüler.
Jørgen Skår Fischer

1
Merhaba Jørgen, colourBrightness betiğinin amacınıza hizmet edebileceğini düşünüyorum: github.com/jamiebrittain/colourBrightness.js
cptstarling

5

ES6 kullanıyorsanız, hex'i RGB'ye dönüştürün, sonra bunu kullanabilirsiniz:

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

İşte girişimim:

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

Sonra kullanmak için:

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

Bu hemen, metni uygun şekilde siyah veya beyaz hale getirecektir. Simgeleri yapmak için:

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

Sonra her bir simge gibi görünebilirdi 'save' + iconSuffix + '.jpg'.

Bunun, herhangi bir konteynerin üstünden taşması durumunda çalışmayacağını unutmayın (örneğin, CSS yüksekliği 0 ise ve taşma gizli değilse). Bunu çalışmak çok daha karmaşık olurdu.


1

Cevapları birleştirerek [@ alex-ball, @jeremyharris] bunun benim için en iyi yol olduğunu buldum:

        $('.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>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.