Modern browsers do the smart thing: they ask the operating system. The OS interacts with hardware all day long; that's its main purpose. So it is in the right place to gather randomness and mix it with a properly secure cryptographic random number generator. On Windows systems, this is made available to application though the
CryptGenRandom() function. Linux has the special file
/dev/urandom for that. Some programming languages offer their own API for that (which internally feeds on the OS), e.g.
java.security.SecureRandom for Java.
The hardware sources that the OS may employ primarily includes the cycle-accurate time at which hardware events occur (e.g. the precise nanosecond at which you press a key, or a network packet is received). The OS can thus get "enough" true randomness to power a RNG, which will then yield good alea by the megabyte ("good" = "indistinguishable from true randomness, up to an overwhelming work factor" = "good for crypto").