Black and white are not colours here
In Unicode character names BLACK means filled and WHITE means hollow. ♡ U+2661 WHITE HEART SUIT is the outline and ♥ U+2665 BLACK HEART SUIT is the solid one, and both are drawn in whatever colour the surrounding text is: put ♥ in red text and it is red. So the way to get a black heart out of this set is the solid character in black text — the character supplies the shape, the stylesheet supplies the colour. A heart that carries its own colour regardless of the text is a separate emoji character, U+1F5A4 BLACK HEART, which is not in the set generated for this page.
The four come from two different places
♡ and ♥ are the card-suit hearts and belong with the other three suits, which are on card suit symbols. ❤ U+2764 HEAVY BLACK HEART and ❥ U+2765 ROTATED HEAVY BLACK HEART BULLET come from the dingbats, a set of printers' ornaments — hence the heavier stroke. ❥ is named a bullet because that is its job: the mark at the start of a list item, drawn on a slant.
❤ has a text form and an emoji form, and you can ask for either
Two invisible characters decide the request. U+FE0F VARIATION SELECTOR-16, placed immediately after the heart, asks for the emoji form; U+FE0E VARIATION SELECTOR-15 asks for the plain text form. They are real characters with a real cost: a field that counts characters counts them, a truncation can cut one off and change what you asked for, and a string that looked like one character is two. A renderer with no emoji form for the preceding character ignores the selector and you are left carrying an extra invisible character for nothing.
Width, when they sit in a column
♡ and ♥ have East Asian width Ambiguous; ❤ and ❥ are Neutral. In a terminal set to render ambiguous characters wide, ♥ takes two cells while ❤ takes one, so a padded list of hearts stops lining up. That is a property of the characters, not of the font — swapping the font does not fix it, and swapping to one heart throughout does.
What a field does to them
All four are general category So — symbols, not letters or digits. A validator that permits "letters, digits and spaces" rejects all four, and a username field that strips non-ASCII drops them silently while leaving the rest of the string intact, which is the version hardest to notice. None of the four is representable in latin-1, so a channel that is genuinely latin-1 cannot carry them at all. NFKC leaves all four unchanged, so normalisation is not what will lose them — the encoding is.
The general reference is symbols to copy and paste, and the wider set, including the ones that are not suits or dingbats, is on heart symbols.