SharePoint v3 was the huge benefactor of the ASP.NET team taking the Web Part framework and adding it to the core ASP.NET 2.0. Since SharePoint is
not now built on top of ASP.NET 2.0, it no longer has its own Web Part implementation... instead it completely relies on the ASP.NET 2.0 framework. Yes, there is a WebPart class in the SharePoint assemblies, but we are not supposed to use it as it is only there for backwards compatibility; it makes Web Parts built in WSS v2 / SPS 2003 work in WSS v3 / MOSS 2007. Instead we should always create ASP.NET 2.0 Web Parts for SharePoint and that is the official recommendation by Microsoft.
When building custom Web Parts, you always hear people say "don't use Render(), only use RenderContents() or use the more OO approach and implement CreateChildControls()." Personally I favor the latter approach of using CreateChildControls(). So why should you not use Render()? Because unbeknownst to you, you are actually breaking something quite powerful.
We all know the browser DOM... but did you know SharePoint has its own DOM? It is called the Web Part Page Services Component, aka WPSC (no, I didn't forget a 'P', don't ask me why there is only one in the acronym :)). I wrote about this in one of my two chapters I contributed to a WSS v3 dev book. Basically the WPSC provides developers with a SharePoint specific client-side DOM that allows developers to listen for events, interact with Web Parts and even set properties... all through script on the client. The WPSC is implemented using a bunch of client-side code. You can see a snippet of it if you look at the source of a SharePoint page... for example, here's the very end of the homepage of the SharePoint Conference 2008 page (implemented using MOSS 2007 WCM... wahoo!):
See all those varPartWPQ# variables? Those are pointing to a specific Web Part in a client-side object. Using this object you can get values from some public properties of the Web Part... very cool!
But wait... there's more! There are also two other properties you can use to get access to the rendered Web Part. First, take a look at how ASP.NET renders Web Parts:
Web Parts are rendered in an HTML <TABLE> with two rows, each row containing one cell (shown in red in the previous image). The top cell contains the header of the Web Part, the bottom cell contains a HTML <DIV> (shown in blue in the previous image) which contains the rendered Web Part. When SharePoint renders the page, it adds a unique ID to the HTML <TABLE> as well as a unique ID to the <DIV>... developers can use these ID's to get to the Web Part via client-side code. Great... so why did I just go through all that? Because when you use RenderContents() or CreateChildControls(), the rendered markup produced by those methods is put inside the <DIV>. If you override Render(), you are replacing the entire <TABLE>! Thus, by replacing the entire table, you are breaking the WPSC... the whole SharePoint specific DOM!
This is just one reason, albeit a big one, why we all say you should use RenderContents() or CreateChildControls()... you should never use Render() when creating Web Parts. Never never never use Render() (hey recruiters, this is a great interview question for prospective SharePoint developers)!
Let's switch gears and talk about accessibility. There are always those who believe table-based design is evil and pixel perfect design (ala CSS-based layout) is the way to go. I'm not stepping into that fray in this post. But let's take a look at the CSS based implementation. Some kits like the Accessibility Kit for SharePoint, a fantastic educational tool (note: it is not a turn-key solution), show how you can implement an accessible site using the CSS-layout approach. One thing they do is leverage control adapters to change the rendering of the stock ASP.NET 2.0 and SharePoint controls. However one that is missing is adapters for the Web Part and Web Part Zone controls.
Lots of people complain about this and go about building their own control adapter to replace the Web Part tables as CSS. That's all fine and good, but they are breaking the WPSC. Now... I fully acknowledge that not many people leverage the WPSC. Heck, I bet many people didn't even know it existed. If you elect to build your own control adapter to get rid of the HTML table, just know that you are implementing a solution to a problem, but by doing so, you are introducing a new problem. Granted, the new problem (a broken WPSC) may not outweigh the need for a CSS-based layout so it may be ok. Thus your mileage may very. At least you now know what you're doing.