Difficulty is a multiple of the minimum amount of Proof of Work (PoW) any valid block can contain. In Bitcoin, the minimum difficulty (called difficulty 1) is defined in the code by this byte mask:
consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
That is, a hash must start[*] with 8 hexadecimal zeros. That's 4 zero bytes, or 32 zero bits.
If you double that difficulty, that's difficulty 2. Double it again and it's difficulty 4, then 8, then 16. At difficulty 16, the hash must have at least 8 + 1 = 9 zeros. Double it again and it's 32, then 64, then 128, then 256. At difficulty 256, the hash must have a minimum of 8 + 2 zeros. Et cetra...
As I write this, the current difficulty is 4306949573981.513. We can see how many minimum zeros that corresponds to by taking its binary log, dividing by the 4 bits that are in in half a byte (one hexadecimal character) and adding the eight zeros from the minimum difficulty:
log2(4306949573981.513) / 4 + 8
For comparison, here's the most recent block header hash (reformatted into byte pairs for readability). It has 18 zeros, as expected. (Note: if you do this experiment at home, note that the hashes are always allowed to have more zeros; they just can't have less.)
0000 0000 0000 0000 0023 bfeb 3a02 1b25 7577 9256 7762 275e b72a d88b 7d50 d7f7
[*] Bitcoin is weird. We display hashes backwards from most other software, so the zeros that start a block header hash are actually at end if you use any non-Bitcoin software to do the hashing.