There are many ways to do this, all of them involve to get rid of the DOM styles since it's impossible to do it without these "tricks". Here's a sample by Chris Coyier (just read the page, skip step 1 and simply prepare teh images and CSS)
/*
Hide the original radios and checkboxes
(but still accessible)
:not(#foo) > is a rule filter to block browsers
that don't support that selector from
applying rules they shouldn't
*/
li:not(#foo) > fieldset > div > span > input[type='radio'],
li:not(#foo) > fieldset > div > span > input[type='checkbox'] {
/* Hide the input, but have it still be clickable */
opacity: 0;
float: left;
width: 18px;
}
li:not(#foo) > fieldset > div > span > input[type='radio'] + label,
li:not(#foo) > fieldset > div > span > input[type='checkbox'] + label {
margin: 0;
clear: none;
/* Left padding makes room for image */
padding: 5px 0 4px 24px;
/* Make look clickable because they are */
cursor: pointer;
background: url(off.png) left center no-repeat;
}
/*
Change from unchecked to checked graphic
*/
li:not(#foo) > fieldset > div > span > input[type='radio']:checked + label {
background-image: url(radio.png);
}
li:not(#foo) > fieldset > div > span > input[type='checkbox']:checked + label {
background-image: url(check.png);
}