For sites where the input is meant to be plain text, the fix is simple: escape everything as it is output as HTML, using an escaping mechanism appropriate to where it is.
Your choice of server-side libraries may affect how easy it is to get this right. If your HTML generation is based on concatenating strings and calling functions to escape variables that might contain certain characters, security depends on "remembering to escape" every variable. One alternative is to use an API where you're constructing a DOM tree out of elements and text nodes. Another is to use an API where you're opening tags, giving them attributes, closing tags, and outputting text. If implemented well, these abstractions might make server-side programming easier and improve a site's speed in addition to making the code less error-prone.
To be safe from XSS, sites should also specify the character set of every page. Browsers use all kinds of crazy heuristics to determine the character set when it is not specified, and the inputs to the heuristics are more or less control of an attacker. For example, browsers may take the character set of the linking page, byte distributions within the page, and the user's language into account. Some character sets (such as UTF-7) have ways of representing the < character without using the byte corresponding to that character in ASCII, which can lead to XSS if a browser thinks your site is UTF-7.