Добрый день уважаемые. Столкнулся с не пониманием почему 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>
После вашего вопроса, я заинтересовался и начал усиленно гуглить.
$(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));
Только вам придется доп. округлять
Даже если обратиться напрямую к стилям (что в некоторых случаях работает хорошо), невозможно никаким образом получить ни 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)
Посоветовали реализовать мою задумку через перебор
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>
Сборка персонального компьютера от Artline: умный выбор для современных пользователей