Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Theme stylesheet rendering

When a page with theme is rendered, the stylesheets link tags in the given theme are rendered right before the closing head tag. Does anyone know of a way to change that? Is there a way that I could have those tags be placed right after the opening head tag?

I know it can be down with jquery by just selecting all the link tags and placing it right after the opening head tag, but is there a way to set it on the server end?

Clarification Let us say I have a single css file (themed.css) in my theme. In that css file, I have a single style definition for a div tag with an id of test:

#test {background-color:red; color:white;}

Let us also say I have a second css file (standard.css) that is NOT in my theme, but it has another definition of the div tag with an id of test:

#test {background-color:yellow;}

I have my page to use the theme, and I have a handwritten link tag to use standard.css. When the page is executed, the link tag for standard.css is before themed.css. When that happens my div tag with id of test has a red background and white forecolor. If I want the themed.css to apply and then standard.css to overwrite the necessary properties (yellow background with white forecolor), I would want themed.css and THEN standard.css. I can't do that because ASP.NET places the theme files right before the closing head tag.

I don't want to have to know that my theme's css files are the nth link tag in my head tag and then manual change any index whenever i may add a new css file outside of my theme.

Thanks!

like image 524
Dan Appleyard Avatar asked May 26 '10 22:05

Dan Appleyard


2 Answers

I did a little checking in Reflector, and found something you may find interesting. The framework calls the SetStyleSheet method of a PageTheme-derived object to inject link controls in the header. This code snippet shows the relevant logic:

int num = 0;
foreach (string str in this.LinkedStyleSheets)
{
    HtmlLink child = new HtmlLink { Href = str };
    child.Attributes["type"] = "text/css";
    child.Attributes["rel"] = "stylesheet";
    if (this._styleSheetTheme)
        this.Page.Header.Controls.AddAt(num++, child);
    else
        this.Page.Header.Controls.Add(child);
}

Translation? StyleSheetThemes inject the style sheets at the beginning of the header tag, and Themes inject the style sheets at the end.

This is consistent with the intended difference between themes and stylesheet themes; that is, that a theme always wins when there is a conflict between the skin and the control settings. Sure, a style in a non-themed .CSS file using the !important attribute could still override a theme style, but the positioning of the CSS files within the head tag strategically facilitates override-ability stylesheet themes.

Note that you can have both a stylesheet theme and a regular theme. Naturally, leave to the stylesheet theme things you design to be override-able, and to the theme things that should not be overridden.

One final observation is that the method is internal and non-virtual, so interfering with these two options would take some kung-fu-MMA-mad-reflection skills, and is probably not in the best interest of stability or maintainability.

like image 85
kbrimington Avatar answered Oct 10 '22 14:10

kbrimington


As soon as your head element has runat="server" you can rearrange the collection in Page_PreRender:

    protected void Page_PreRender(object sender, EventArgs e)
    {
        ControlCollection container = this.Page.Header.Controls;
        foreach (var control in container.OfType<System.Web.UI.HtmlControls.HtmlLink>().ToArray())
        {
            container.Remove(control);
            container.AddAt(0, control);
        }
    }
like image 20
UserControl Avatar answered Oct 10 '22 16:10

UserControl