Firstly, why are you implementing low-level crypto code for a web page? You'd think this is a solved problem: you use a framework which uses libraries.
Secondly, the hash protect the passwords in case that the hashes leak out. Your site does not provide access to the password database, so this situation should ideally not even arise. The salts help to defend the password database as a whole in that event.
If the attacker is focused on a single password out of that database, then it doesn't make much difference. It only makes the job harder in the sense that the attacker can't just retrieve the password from a rainbow table by looking up the hash. The brute-forcing of a password with a salt is only slightly slowed down because a few more bytes are hashed which costs a few more machine cycles in the hashing rounds.
Once upon a time, Unix systems providing public access (such as campus systems for students) had their passwords cracked left and right. There were various reasons why this was easy, but the main problem was a simple one: the sensitive password hash information was kept in the same file as the other information fields about a user, and that file,
/etc/passwd was world-readable. The fix is to put the sensitive information into a separate file,
/etc/shadow. Presto: that ends the password cracking by script kiddies who have unprivileged, legitimate accounts on the system.
Similarly, nobody is going to be brute forcing your passwords unless you let them leak out.
If they leak out and someone is after a particular user's password, there is little that can be done to stop them.
Users who use the same passwords on different systems and don't change it for years and
years are always going to be vulnerable. You can salt it, pepper it and add ketchup; won't make a difference.
Salts do deter someone who wants to crack the password database as a whole and gather as many different passwords as possible. Salts mean that each password has to be brute-forced individually rather than just retrieved from pre-computed tables. If a salt has N bits, then, at least ideally, the attacker's rainbow table database has to be 2^N times larger. A 32 bit salt means you need a four billion times larger rainbow table database to just look up passwords.
If your site only has 20 users, then of course there are only up to 20 different salts. So what an attacker will do is take the password dictionary and hash each entry in 20 different ways with those salts.
So salts not only protect your database against rainbow table lookup, but also protect it from brute force cracking by about a factor of N, where N is the number of users. To brute force N passwords, the attacker has to do N times the work as brute forcing one. (Assuming the salt is wide enough: at least as large as the base 2 logarithm of N. If a salt is only, say, 12 bits wide, then there can only be 4096 different salts, no matter how many users there are.)
Without salts, this is not true. Brute forcing any number of passwords at the same time is as easy as brute forcing one, so the more users there are, the bigger the payoff per effort.