How to split server styles

If you've been developing custom WebControls, in some cases, you may have had to split a server-side style on two HTML elements. Usually we want to apply the border and similar properties to a container like a div or td, and the Font properties and ForeColor to a text element such as a link (because a link forces the color and text-decoration, for example).

If the style is an inline server style (specified in the aspx or ascx using a style property directly on the server control), we know everything about it and we know how to split the properties on the two elements.

Now, if the style just specifies a CssClass, we are doomed because we have no way of knowing what’s inside the class (it’s purely client-side) and even less to split it correctly.

Applying it to only one element does not work because some styles just won’t apply at this level, and applying it to both induces nice effects like double borders or proportional font-sizes being squared:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <style type="text/css">
            .foo {font-size:2em;border-color:black;border-width:1px;border-style:solid}
        </style>
    </head>
    <body>
        <table>
            <tr>
                <td class="foo">
                    <a href="foo.htm" class="foo">This is 4em</a> but this is 2em.
                </td>
            </tr>
        </table>
    </body>
</html>

Renders as:

This is 4em but this is 2em.

You can partially solve this problem by applying the CssClass to both elements, and adding an inline style to the inner tag to suppress the second border and the size multiplication if a CssClass is present:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <style type="text/css">
            .foo {font-size:2em;border-color:black;border-width:1px;border-style:solid}
        </style>
    </head>
    <body>
        <table>
            <tr>
                <td class="foo">
                    <a href="foo.htm" class="foo" style="border-style:none;font-size:1em">This is 2em</a> and this too.
                </td>
            </tr>
        </table>
    </body>
</html>

Renders as:

This is 2em and this too.

You could also add a second property (something like TextCssClass) on relevant Style-derived classes to enable the splitting of the style class by the users. This would be a good solution because it matches exactly what you are doing on inline styles, but it adds a new property, participating in a complexification of your control's object model, possibly confusing users who may not know about this style-splitting problem. It may simplify the implementation of the rendering of your control, though. So if you can do it, it's probably the best solution.

There is a workaround that solves the problem just by writing the CSS file a certain way, though, splitting the styles from there instead of from the control. It requires no modification of the object model but requires some knowledge of the rendering for the control (we need the name of the tag for the container and for the text HTML nodes to be predictable and stable):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <style type="text/css">
            td.bar {border-color:black;border-width:1px;border-style:solid;color:red}
            a.bar {font-size:2em}
        </style>
    </head>
    <body>
        <table>
            <tr>
                <td class="bar">
                    <a href="foo.htm" class="bar">This is 2em</a> but this is not.
                </td>
            </tr>
        </table>
    </body>
</html>

Renders as:

This is 2em but this is not.

Here, we just split the definition of the bar class in two classes with the same name, but applying only to one tag name at a time.

This is a suitable workaround if you can't use the second solution (the additional CssClass property on the style class) because it gives maximum flexibility to the user while requiring no modification on the WebControl's object model. It requires good documentation, though, so that the users can learn about this workaround when they hit the problem.

No Comments