Thursday, June 21, 2007

Slaying CSS bugs with AJAX for ASP.NET

Recently I've been working on an ASP.NET project and am writing a whole host of custom controls. I really can't emphasize enough the power of custom controls. They are code which writes code, allowing you to build DSL's for expressing user-interface elements.

When building custom controls it's nice to make the elements in the control scale with the size of the control itself. This probably means that you will be using tables for any sufficiently complex control. Unfortunately in IE 5 and 6, if you nest a textbox inside of a table cell and make its width 100% the end of the textbox get's cut off thusly:



Attempts to correct this by specifying a value for margin-right are rudely ignored by IE. You can test this yourself by trying out the following code:


<span ><span id="ctl00_Main_PercentField1" style="display:inline-block;width:50px;"><table border="0" style="width:100%;"></span>
<span style="font-family: courier new;"> <tr></span>
<span > <td><div><input name="ctl00$Main$PercentField1$TextBox1" type="text" value="23" id="txt" style="width:100%"></div></td></span>
<span style="font-family: courier new;"> </tr></span>
<span ></table></span></span>

After confirming that this problem was a known bug I did the first thing most developers do: I bitched and moaned. There is not much web developers can do about browser CSS bugs. Or can they?

I've been doing heavy DHTML programming since the days of IE4 and am aware of a little known property called clientWidth. This property gives you access to the actual width of a UI element in pixels. All I needed to do, I figured was get the textbox using the DOM methods and set the CSS width to the clientWidth and subtract some absolute value. Sure enough it worked like a charm. Ten pixels is the magic number for some reason.



In addition to custom controls I've also been writing control extenders using AJAX for ASP.NET. I've complained about AJAX for ASP.NET in the past but I must admit it's a very elegant way of encapsulating javascript behaviors. It was child's play to create a custom extender that I could point to a textbox that was positioned inside a table. Here is the code:

FixTextBoxWidthBehavior.js
----------------
Type.registerNamespace('TheMechanicalBride')

TheMechanicalBride.FixTextBoxWidthBehavior = function(element)
{
GE.Water.Web.FixTextBoxWidthBehavior.initializeBase(this,[element]);

}

TheMechanicalBride.FixTextBoxWidthBehavior.prototype = {

initialize: function()
{
TheMechanicalBride.FixTextBoxWidthBehavior.callBaseMethod(this,'initialize')

var e = this.get_element();
e.style.width = "" + (e.clientWidth-10) + "px"


},

dispose : function()
{
TheMechanicalBride.FixTextBoxWidthBehavior.callBaseMethod(this,'dispose')


}
}

TheMechanicalBride.FixTextBoxWidthBehavior.registerClass('TheMechanicalBride.FixTextBoxWidthBehavior', AjaxControlToolkit.BehaviorBase);



------------------

FixTextBoxWidthExtender.vb
---------------------




Imports System
Imports System.Web.UI.WebControls
Imports System.Web.UI
Imports System.ComponentModel
Imports AjaxControlToolkit


<Assembly: WebResource("TheMechanicalBride.FixTextBoxWidthBehavior.js", "text/javascript")>

Namespace UI.WebControls

<ClientScriptResource("GE.Water.Web.FixTextBoxWidthBehavior", "GE.Water.Web.FixTextBoxWidthBehavior.js")> _
<TargetControlType(GetType(TextBox))> _
<RequiredScript(GetType(CommonToolkitScripts), 0)> _
Public Class FixTextBoxWidthExtender
Inherits ExtenderControlBase

Public Sub New()

End Sub

End Class

End Namespace



And that's it. The lesson: in the age of modern browsers you don't always have to accept CSS bugs. Get hacking.

8 comments:

Terry Thibodeau said...

I can't believe you blogged about this!!!

I've been going ABSOLUTELY NUTS with this EXACT problem for the past 2 days. I couldn't find any solutions when doing Google searches. I'd finally just resigned myself to the fact that this was a stupid sizing bug and hacked around it by making my text inputs 98% instead of 100%.

I used to do the same kind of thing back in the day with element behaviours (.htc files). It's nice to see client-side code reusability stepped up. :)

Instead of using a "magic number" of 10 for your width adjustment, couldn't you use the parent element's padding value? I'm assuming that 10 works because of the table cell padding value you're using. Just a thought.

Great post! Thanks!

Cads said...

Nice Post, I tend to use width at 99% as well, its a really weird bug!

Jafar Husain said...

Good point Terry,

I just thought of the padding last night in bed! That can definitely be arranged. Also I've changed the behavior to listen for the window's onresize event. When the size of the window changes I set the width back to 100% and then apply the fix again just in case the parent control has percent-based width.

The difficulty with including padding is that to do it properly I'll have to recurse up all of the parent elements of the textbox because CCS properties are inherited. Technically I believe it can be done, I'm just not really that interested in doing it :-) The only case I'm really interested in for creating web controls is where I need something to be 100% but it gets cut off. I'd be eager to hear from you if you figure out a way to do padding properly.

Anonymous said...

Hey, while searching for widgets for my blog, I stumbled upon www.widgetmate.com and wow! I found what I wanted. A cool news widget. My blog is now showing latest news with title, description and images. Took just few minutes to add. Awesome!

Affordable Luxurious Wedding Dress Blog said...

cheap wedding gowns,
discount bridal gowns,
China wedding dresses,
discount designer wedding dresses,
China wedding online store,
plus size wedding dresses,
cheap informal wedding dresses,
junior bridesmaid dresses,
cheap bridesmaid dresses,
maternity bridesmaid dresses,
discount flower girl gowns,
cheap prom dresses,
party dresses,
evening dresses,
mother of the bride dresses,
special occasion dresses,
cheap quinceanera dresses,
hot red wedding dresses

products said...

China Wholesale has been described as the world’s factory. This phenomenom is typified by the rise ofbusiness. Incredible range of products available with China Wholesalers “Low Price and High Quality” not only reaches directly to their target clients worldwide but also ensures that wholesale from china from China means margins you cannot find elsewhere and buy products wholesaleChina Wholesale will skyroket your profits.

products said...

Women’s nike tn Shox Rivalry est le modèle féminin le plus tendance de baskets pour le sport. tn chaussuresConcernant la semelle :Cheap Brand Jeans ShopMen Jeans - True Religion Jeans nike shoes & Puma Shoes Online- tn nike, le caoutchouc extérieur, l’EVA intermédiaire et le textile intérieur s’associent pour attribuer à la.ed hardy shirts pretty fitCharlestoncheap columbia jackets. turned a pair of double plays to do the trick.Lacoste Polo Shirts, , Burberry Polo Shirts.wholesale Lacoste polo shirts and cheap polo shirtswith great price.Thank you so much!!cheap polo shirts men'ssweate,gillette mach3 razor bladesfor men.As for

Anonymous said...

情趣用品|情趣用品|情趣用品|情趣|情趣用品|情趣

About Me

My photo
I'm a software developer who started programming at age 16 and never saw any reason to stop. I'm working on the Presentation Platform Controls team at Microsoft. My primary interests are functional programming, and Rich Internet Applications.