The snapshots are not really stored per-se. Think of it this way. Every time you write a block to the disk, a time stamp is written to this block as well, that indicates when the write took place.
Now when you change a file, instead of the old block that contained the file getting overwritten, a new block is written with the file in it, along with a new time-stamp.
The directory entry for the directory containing the file, which itself is also a block with a timestamp, is then also rewritten to point to the new block. This directory change again is to a new block with a new timestamp.
So now a snapshot is nothing more than a timestamp itself. Using the snapshot's timestamp, you can reconstruct what the drive looked like at that time, by looking at all the block timestamps.
There are now some intricacies based on how often you "take a snapshot" that dictate which of the old blocks actually need to be retained. It is easy to see that if a file got written to in 2008 and 2009, but the earliest snapshot that exists on the machine is from 2010, there is no way to get the 2008 version back by reverting to a snapshot, so the blocks associated with that 2008 version can be returned to the pool of free disk space.
There are similar rules which dictate which blocks need to be retained for files that get modified multiple times in between two snapshots.
So you can see that a snapshot initially takes up no space at all. It is when you start modifying files after a snapshot is taken, that blocks that would normally become free disk space, will now need to be retained in order to be able to revert to an older version of the file. These blocks can be released back to the pool when the last snapshot older than the affected block is deleted.
Of course in ZFS all this is implemented in very clever ways so that it doesn't make the entire volume dog slow. :D