简体   繁体   中英

Efficient way of changing background color of an element in CSS3 or HTML5

I need to change each item's color in a list after a reorder or removing one item, now I am using jquery's css method like below

$('li').css('background-color', color);

It works, but terribly slow, and sometimes the page will render the color incorrectly, even on Chrome, which is supposed to be fast. The list doesn't have many items, below 10, usually 5 - 7. So this performance is not acceptable. So I want to know if there is a better, faster way in CSS3, or HTML5. If not, if there is an walkaround or some kind of jquery solution?

The code for refreshing list items' color is as below. The index can be decided by a function and the color can decide color by it. The major issue I think is that changing background color trigger reflow or maybe rerendering.

function refreshListItemColor(liElements, colorGetter, indexGetter) {
        colorGetter = colorGetter || (function (color) {
            return color;
        });
        indexGetter = indexGetter || (function (liElement, index) {
            return index;
        });
        liElements.each(function (index, liElement) {
            index = indexGetter(liElement, index);
            var data = ko.dataFor(liElement);
            var indexColor = colorForIndex(index);
            indexColor = colorGetter(indexColor, data);
            if (indexColor !== $(liElement).css('background-color')) {
                $(liElement).css('background-color', indexColor);
            }
        });
}

Update : using element.style['background-color'] won't do. The issue still remains. Another possible explanation for the lagging is that every list item itself has about 10 child elements, making change list item's color particularly expensive.

Update2 : I'll try to ask a related question: is there a way to change the color of the background of the parent node without triggering a rerender of children elements?

Update3 : I tried to add delay for each color change operation, like below

var delay = 100, step = 100;
liElements.each(function (index, liElement) {
    index = indexGetter(liElement, index);
    var data = ko.dataFor(liElement);
    var indexColor = colorForIndex(index);
    indexColor = colorGetter(indexColor, data);
    if (indexColor !== $(liElement).css('background-color')) {
        setTimeout(function () {
            liElement.style['background-color'] = indexColor;
        }, delay);
        delay += step;
    }
});

It seems can alleviate this issue a lot. I guess this will not solve the problem, but will reduce the impact to an acceptable level.

Could you use attribute selectors in your stylesheet?

[data-row="1"][data-col="3"]{
    background-color: blue;
}

I noticed that If you want to select a whole row or column you have to use !important

[data-col="3"]{
    background-color: blue !important;
}

CSS更改


(edit)Adding styles dynamically
Create a empty style tag with a div

<style type="text/css" id="dynamicstyle"></style>

and just append to it like any other tag

$("#dynamicstyle").append('[data-row="0"]{background-color:red !important;}');

for your case you can check whenever an element is added and add a row style since in theory the user could pile up all of the elements.

$(function () {
var maxRows = 0;
$("ul").bind("DOMSubtreeModified", updateStyleSheet);

function updateStyleSheet() {
    var childCount = $("ul").children().length;
    if (maxRows < childCount) {
        maxRows = childCount;
        var newRule = [
            '[data-row="',
        maxRows,
            '"]{background-color:', ((maxRows % 2) ? "red" : "blue"),
            ' !important;}'].join('')
        $("#dynamicstyle").append(newRule);
    }
}
});

http://jsfiddle.net/PgAJT/126/

FizzBuzz rows http://jsfiddle.net/PgAJT/127/

Remove your "if", which may force browser to redraw/recompile/reflow latest CSS value.

if (indexColor !== $(liElement).css('background-color')) {

Yes, read are slow and as they will block write-combine.

Presumably, the colour is determined by the position of the element in the list.

Use nth-child or nth-of-type selectors in your stylesheet.

Hi i have just tried wat u need just check it..

http://jsbin.com/awUWAMeN/7/edit

function change()
{
  var colors = ['green', 'red', 'purple'];
alert(colors)
$('.sd-list li').each(function(i) {
    var index = $(this).index();

        $(this).css('background-color', colors[index]);

});

}

I've created a simple test with 10 list items, each with 12 children and setting the background colour for every item each time Gridster's draggable.stop event fires. The change is pretty much instantaneous in IE11 and Chrome.

To me, this suggests it isn't the CSS rendering that's slow, but maybe the calculations determining which colours are for which elements.

This is the JavaScript I was using:

var colors = ['#000', '#001', '#002', '#003', '#004', '#005', '#006', '#007', '#008', '#009', '#00a', '#00b'];

$('.gridster ul').gridster({
    widget_margins: [10, 10],
    widget_base_dimensions: [120, 120],
    draggable: {
        stop: function (e, ui, $widget) {
            refreshListItemColor();
        }
    }
});

function refreshListItemColor() {
    var sortedElements = [];
    $('ul > li:not(.preview-holder').each(function () {
        sortedElements.push([this, this.getAttribute('data-col'), this.getAttribute('data-row')]);
    });

    sortedElements.sort(function (a, b) {
        return a[1] - b[1] || a[2] - b[2];
    });

    for (var i = sortedElements.length - 1; i >= 0; i--) {
        sortedElements[i][0].style.backgroundColor = colors[i];
    }
}

How are you determining which colours to set on each list item?

I've find it fast to create a class with the css attributes you want and then add that class to the dom element you want the css attribute applied to. CSS rules appear without refresh.

css:

.bg-green{
background:green;
}

js:

$("#someDomId").toggleClass('bg-green','add');

A cool way of dealing with lists is to index the id of each list element as you create/alter it:

Create list:

for (i=0;i=m;i++){
var listElement = "<li id='"+i+">Some Content</div>";
$('ul').append(listElement);
}

Then instead of iterating through a dom element (which is expensive) you can run another for loop and alter each list element by selecting it's id.

for (i=0;i=m;i++){
$("#"+i).toggleClass('bg-green','add');
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM