Почему возвращает значения RGB каналов?

494
06 февраля 2017, 18:10

Добрый день уважаемые. Столкнулся с не пониманием почему JS возвращает значения RGB каналов хотя в CSS задаю под HSL. В целом задача состоит такая- необходимо каждые две секунды менять значения цветов у квадратов. Первый и второй блоки (столбци) квадратов должны получать +10 к hue каналу каждые две секунды ( То есть после второй секунды у классов .first_st* должны быть значения h =11 а у классов .second_st* = 21 ). Если значения h доходят до 360 то добавляется сколько возможно а затем всё стартует с нуля. (То есть на 36 итерации у классов .first_st* должны быть значения h =1 а у классов .second_st* = 11) Приведу код:

	var allFirstColors = $("[class^='first_st']"), 
		firstColorsLength = allFirstColors.length, 
 
		allSecondColors = $("[class^='second_st']"), 
		secondColorsLength = allFirstColors.length; 
 
	var h,s,l; 
 
		console.log(" st1 = " + $(".first_st1").css("fill") ); // Почему возвращает RGB каналы?  
 
		allFirstColors.each(function(indx, el){ 
				let  color = $(el).css("fill"), 
				[h,s,l] = color.match(/\d+/g); 
	console.log("[h,s,l] = " + [h,s,l]); 
		});	
.first_st1{ 
			fill: hsl(1, 50%, 50%); 
		} 
		.first_st2{ 
			fill: hsl(1, 70%, 40%); 
		} 
		.first_st3{ 
			fill: hsl(1, 90%, 30%); 
		} 
 
		.second_st1{ 
			fill: hsl(11, 50%, 50%); 
		} 
		.second_st2{ 
			fill: hsl(11, 70%, 40%); 
		} 
		.second_st3{ 
			fill: hsl(11, 90%, 30%); 
		}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<svg width="600" height="240"> 
		<rect class="first_st1" width="80" height="80" x="0" y="0"></rect> 
		<rect class="first_st2" width="80" height="80" x="0" y="80"></rect> 
		<rect class="first_st3" width="80" height="80" x="0" y="160"></rect> 
 
		<rect class="second_st1" width="80" height="80" x="160" y="0"></rect> 
		<rect class="second_st2" width="80" height="80" x="160" y="80"></rect> 
		<rect class="second_st3" width="80" height="80" x="160" y="160"></rect> 
	</svg>

Answer 1

После вашего вопроса, я заинтересовался и начал усиленно гуглить.

$(el).css() по сути возвращает вам свойства из getComputedStyle(el), а getComputedStyle(el) возвращает высчитанные(resolved) свойства, т.е. браузеры сами конвертируют ваш цвет в rgb(a) и возвращают его и работать с тем что вы написали у вас не получиться, поэтому придется конвертировать вручную в нужный вам формат.
Например если выставить width:100%;, то getComputedStyle вернет вам длину блока в px, а не 100%.

Вот ниже нашел функцию которая по формуле из вики конвертирует rgba в hsl.

function rgbToHsl(r, g, b){ 
    r /= 255, g /= 255, b /= 255; 
    var max = Math.max(r, g, b), min = Math.min(r, g, b); 
    var h, s, l = (max + min) / 2; 
 
    if(max == min){ 
        h = s = 0; // achromatic 
    }else{ 
        var d = max - min; 
        s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 
        switch(max){ 
            case r: h = (g - b) / d + (g < b ? 6 : 0); break; 
            case g: h = (b - r) / d + 2; break; 
            case b: h = (r - g) / d + 4; break; 
        } 
        h /= 6; 
    } 
 
    return [h, s, l]; 
} 
 
console.log(rgbToHsl(191, 66, 63));

Только вам придется доп. округлять

Answer 2

Даже если обратиться напрямую к стилям (что в некоторых случаях работает хорошо), невозможно никаким образом получить ни hex, ни hsl значения. Только специальное обозначение типа "red":

function getStyle(className) { 
    var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules; 
    for (var x = 0; x < classes.length; x++) { 
        if (classes[x].selectorText == className) { 
            (classes[x].style.cssText) ? console.log(classes[x].style.cssText) : console.log(classes[x].cssText); 
        } 
    } 
} 
getStyle('.first_st1'); 
getStyle('.first_st2'); 
getStyle('.first_st3');
.first_st1 { 
  fill: red; 
} 
.first_st2 { 
  fill: #ff5555; 
} 
.first_st3 { 
  fill: hsl(1, 90%, 30%); 
} 
.second_st1 { 
  fill: hsl(11, 50%, 50%); 
} 
.second_st2 { 
  fill: hsl(11, 70%, 40%); 
} 
.second_st3 { 
  fill: hsl(11, 90%, 30%); 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<svg width="600" height="240"> 
  <rect class="first_st1" width="80" height="80" x="0" y="0"></rect> 
  <rect class="first_st2" width="80" height="80" x="0" y="80"></rect> 
  <rect class="first_st3" width="80" height="80" x="0" y="160"></rect> 
 
  <rect class="second_st1" width="80" height="80" x="160" y="0"></rect> 
  <rect class="second_st2" width="80" height="80" x="160" y="80"></rect> 
  <rect class="second_st3" width="80" height="80" x="160" y="160"></rect> 
</svg>

Поэтому, хорошим способом решить проблему будет использование data-* тегов:

var allFirstColors = $("[class^='first_st']"), 
  firstColorsLength = allFirstColors.length; 
 
var h, s, l; 
 
console.log(" st1 = " + $(".first_st1").css("fill")); 
 
allFirstColors.each(function(indx, el) { 
  let color = $(el).data("hsl"), 
    [h, s, l] = color.match(/\d+/g); 
  console.log("[h,s,l] = " + [h, s, l]); 
});
.first_st1 { 
  fill: hsl(1, 50%, 50%); 
} 
.first_st2 { 
  fill: hsl(1, 70%, 40%); 
} 
.first_st3 { 
  fill: hsl(1, 90%, 30%); 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<svg width="600" height="240"> 
  <rect class="first_st1" data-hsl="1, 50, 50" width="80" height="80" x="0" y="0"></rect> 
  <rect class="first_st2" data-hsl="1, 70, 40" width="80" height="80" x="0" y="80"></rect> 
  <rect class="first_st3" data-hsl="1, 90, 30" width="80" height="80" x="0" y="160"></rect> 
 
 
</svg>

С помощью $(el).data("hsl") получите hsl данные, затем запишите измененные с помощью $(el).data("hsl", h+', '+s+', '+l)

Answer 3

Посоветовали реализовать мою задумку через перебор

window.onload = function(){ 
   
    var initialH1 = 1 
        initialH2 = 11, 
        allFirstColors = $("[class^='first_st']"), 
        firstColorsLength = allFirstColors.length, 
        allSecondColors = $("[class^='second_st']"), 
        secondColorsLength = allFirstColors.length; 
           
    window.setInterval(function(){ 
   
        initialH1 = initialH1 === 360 ? 1 : initialH1 + 10 < 360 ? initialH1 + 10 : 360; 
        initialH2 = initialH2 === 360 ? 11 : initialH2 + 10 < 360 ? initialH2 + 10 : 360; 
           
        allFirstColors.each(function(i){ 
            $(this).css("fill", `hsl(${initialH1}, ${50 + i * 10}%, ${50 - i * 10}%)`); 
  
            console.log( $(this).css("fill") + " = first block" ) 
        }) 
           
        allSecondColors.each(function(i){ 
            $(this).css("fill", `hsl(${initialH2}, ${50 + i * 10}%, ${50 - i * 10}%)`); 
  
            console.log( $(this).css("fill") + " = second block" ) 
  
        }) 
           
    }, 2000) 
}
   .first_st1{ 
            fill: hsl(1, 50%, 50%); 
        } 
        .first_st2{ 
            fill: hsl(1, 70%, 40%); 
        } 
        .first_st3{ 
            fill: hsl(1, 90%, 30%); 
        } 
   
        .second_st1{ 
            fill: hsl(11, 50%, 50%); 
        } 
        .second_st2{ 
            fill: hsl(11, 70%, 40%); 
        } 
        .second_st3{ 
            fill: hsl(11, 90%, 30%); 
        }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<svg width="600" height="240"> 
        <rect class="first_st1" width="80" height="80" x="0" y="0"></rect> 
        <rect class="first_st2" width="80" height="80" x="0" y="80"></rect> 
        <rect class="first_st3" width="80" height="80" x="0" y="160"></rect> 
   
        <rect class="second_st1" width="80" height="80" x="160" y="0"></rect> 
        <rect class="second_st2" width="80" height="80" x="160" y="80"></rect> 
        <rect class="second_st3" width="80" height="80" x="160" y="160"></rect> 
    </svg>

В принципе оно работает, но меня не очень устраивает. Как быть если Значения в блоках совершенно разные, как прописать алгоритм ? Допустим для таких значений ?

.first_st1{ 
            fill: hsl(1, 84%, 61%); 
        } 
        .first_st2{ 
           fill: hsl(358, 83%, 54%); 
        } 
        .first_st3{ 
            fill: hsl(350, 65%, 40%); 
        } 
   
        .second_st1{ 
            fill: hsl(11, 84%, 61%); 
        } 
        .second_st2{ 
            fill: hsl(8, 83%, 54%); 
        } 
        .second_st3{ 
            fill: hsl(0, 65%, 40%); 
        }
<svg width="600" height="240"> 
        <rect class="first_st1" width="80" height="80" x="0" y="0"></rect> 
        <rect class="first_st2" width="80" height="80" x="0" y="80"></rect> 
        <rect class="first_st3" width="80" height="80" x="0" y="160"></rect> 
   
        <rect class="second_st1" width="80" height="80" x="160" y="0"></rect> 
        <rect class="second_st2" width="80" height="80" x="160" y="80"></rect> 
        <rect class="second_st3" width="80" height="80" x="160" y="160"></rect> 
    </svg>

READ ALSO
Загрузилась ли страница на ReactJS

Загрузилась ли страница на ReactJS

Пытаюсь написать модальное окно на React Js, чтоб оно появлялось сразу после загрузки страницыПроверка как в нативном JS через window

429
Перенос блока в начало при нехватке места

Перенос блока в начало при нехватке места

[ Здравствуйте,есть вопрос,как можно перенести последний блок в начало,при нехватке места,чтобы в начало попал только тот кусок,который не влез,а...

562
FileReader &ldquo;Error ProgressEvent&rdquo; на больших файлах

FileReader “Error ProgressEvent” на больших файлах

При загрузке больших файлов (4+ Gb),файлы открываются через стандартную функцию

476