Link to home
Start Free TrialLog in
Avatar of NevinsLtd
NevinsLtd

asked on

styleSheetTheme attaching all css files?

In my web application I have sat the web.config to the following

<pages styleSheetTheme="DetaultTheme" masterPageFile="~/MYMasterPage.master">

Apparently, this attaches all css files to every page in the app.. which is causing some inconstancy or conflicts sometimes..

Questions:
1- Is this how it suppose to be
2- If I remove this setting from web.config and apply css individually to each page as desired .. would that be considered a bad practice, if so what is the best practice.

Thank you,

Avatar of abel
abel
Flag of Netherlands image

I am not sure whether there's really a best practice here, as it depends so much on the style and complexity of the web site whether this is feasible. Personally, I hate putting it inside the web.config, probably because I found it too hidden back there.

Most of the time I end up having a small amount of master pages, that inherit from a single root master page. That root master page designs the important straight parts of the web pages, and the child masters define the sub styles. Often I end up with one or two special masters (i.e., for messages, errors, email confirmation).

Having one global style is then not handy and only complicates things. But having styles in general is not always going to cover you anyway, because some things just cannot be set in style files, you need normal CSS or other styles of programming for that.

Using the method of root > master > page ( > parts) > control has proven well for me. Mimicking that style through themes did not always work well for me. So I often end up creating my own decorator classes, which gave loads of flexibility, but also adds to the overall work. The nice thing about decorators is: if you design them well, you can more easily reuse them in other projects.

Not sure if this comment is going to really help you out with your decision. Bear in mind that there are many ways of dealing with the design(s) of web pages and that there's no single best fit solution.

-- Abel --
you should put all the css styles which are required for the Master File and put all the styles inside individual pages according to there needs.

Try to be specific while creating style classes in order to remove the style conflicts
Avatar of NevinsLtd
NevinsLtd

ASKER

thank you both for your answers.. what I found it strange is that when I attach a styleSheetTheme  to a page (whether there is a master or not) it actually applies (or attach) all css files inside DefaultTheme folder to that page.. I kinda found out that when I did ViewPageSource ..
I thought it will only attach what I ask the page to attach .. btw, does attaching css files affect the page size or page load?
yeah it is right.

If you have some style sheet in master page it will apply all its styles in all pages inside that master and those styles are always available for all the pages.

so if you need separate styles for the pages you will need to remove the name conflicts and add separate styles to individual pages
thanks for the replay .. I understand that part.. perhaps I miss explained myself..
Say I have in the App_Themes folder DefaulltTheme folder and inside the last folder I have 7 different css files.. I have only assigned one style to the master page ONLY one .. now when  I set the web.config to

<pages styleSheetTheme="DetaultTheme" masterPageFile="~/MYMasterPage.master">

By default any page in my app (wither used master page or not) will have ALL 7 CSS attached at run time..
are all the 7 files inside the DefaultTheme folder. Then its obvious that all the 7 files will be included.
you need to keep only the specific requiered file inside the DefaultTheme folder
Thanks Amer...
That is strange .. obviously they all used in the same app but each one designated to different page .. so I thought it wouldn't make sense to have all of them attached, rather only attach the ones that are applicable to that style.
Though they are used in different pages but they will be available in whole application as it is the master page in which you are including them
>  btw, does attaching css files affect the page size or page load?

hardly, the CSS will be downloaded once. The alternative, using inline styles, cannot be cached by browsers and is slower in the long run, both in terms of rendering and in terms of download time.

Long story short: yes, it will affect the page size/load in a positive sense, it will be quicker and smaller.
Reading up on the other comments, here're some answers:

  • Let's make one thing very clear: if you select a Theme, whether on a page, the web.config, in the master, in code behind, even in a control, it will always include all CSS files that are underneath
  • The CSS files will be included in alphabetical order. The last one will have preference when two cascading rules conflict
  • I'm not sure if you can modify a theme on the fly. If so, you might be able to exclude certain CSS files for a particular page
I'll explain with a little more clarity in the next post.

-- Abel --
ASKER CERTIFIED SOLUTION
Avatar of abel
abel
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you for taking the time to explain .. although I'm familiar with the concept, but it was greatly explained..
Great.. it sounds that I shouldn't be too concern about including all css in each file as long as there are no naming conflicts..
my concern was that I like to create css for each page that covers controls are not used in other pages and one or few other css files that have shared styles. The concern here is that if I end up with 25 or 50 css files .. all those will be listed inside that page .. which didn't make sense to me ..

Thanks all for taking the time to explain
Tx for the grade :)

I'd like to give you an idea of tackling this differently. If you want specialized styles per page, you don't want to have to remember all other pages' ids and classes. Probably, these special styles have little to do with the themes you already have (I hope). If so, you can create a simple method that creates a link like "~/css/pages/mypagename.css". That method goes into the page_load of your master_page, dynamically adding a stylesheet link element to the page with the name of the page. That's all.

No special coding per page, and no hundreths of extra CSS's that are loaded. It may not matter to the browser, but it surely doesn't make debugging CSS issues easier.

You can make the method slightly more sophisticated by checking whether that CSS actually is available and then only include it if it is.

On another note, but I didn't find much references on this on the internet, is using the ThemeProvider for your site and the CssFiles selection to see if you can manipulate that somehow.

-- Abel --


Well, that was a nice weekend of research and disassembly to get this thing together. As from all the posts in this thread, you know that the css stylesheets cannot be modified or changed on the fly. Since you have so many of them, I figured there must be an "easy" way to solve this. Well, "easy" is not correct, but consider the following code, which bears the fruits of my research onto the dungeons of themes parsing.

The code uses reflection to gain access to private fields and properties and to set private fields inside dynamically created objects (which the Themes end up being: on the fly created objects with names like ASP.ThemeName). I won't go into too many details, it touches on a couple of very advanced subjects, but using the code should be straightforward.

Just copy the code (and encapsulate it in some nicer class). I underscored these methods to warn any users of the methods that these use undocumented features of dotnet that may change on a next release.

In the OnInit event, before calling base.OnInit(e) (this is vital!), the themes are initialized (happens after PreInit) but not yet applied (happens in Init), you can retrieve the stylesheets with _GetThemeStyleSheets(), which gives a string array and you can set the stylesheets with _SetThemeStyleSheets(string[] array).

yes, it is that easy. But it wasn't easy to dig up this method, and there's not a single reference on the internet that explains you about this...

If you are still listening in, hope it is of some use to you :)

-- Abel --

public partial class ChangeThemeCSSReferencesDynamically : System.Web.UI.Page
{
 
    protected override void OnInit(EventArgs e)
    {
        string[] stylesheets = this._GetThemeStyleSheets();
 
        // remove the redundant stylesheets for the current page
        string[] oneStylesheet = new string[] { stylesheets[0] };
        this._SetThemeStyleSheets(oneStylesheet);
        base.OnInit(e);
    }
 
 
    private PageTheme _GetPageTheme()
    {
 
        FieldInfo fieldInfo = typeof(Page).GetField("_theme",   // why doesn't this.GetType work?
            BindingFlags.GetField | 
            BindingFlags.Instance |
            BindingFlags.FlattenHierarchy |         // why needed?
            BindingFlags.NonPublic);
        return fieldInfo.GetValue(this) as PageTheme;
    }
 
    private string[] _GetThemeStyleSheets()
    {
        PageTheme myTheme = _GetPageTheme();
 
        // myTheme.GetType is necessary (as opposed to typeof(PageTheme), 
        // because it is a runtime-defined type
        PropertyInfo propInfo = myTheme.GetType().GetProperty("LinkedStyleSheets",
            BindingFlags.GetProperty |
            BindingFlags.Instance |
            BindingFlags.NonPublic);
 
        //propInfo.GetGetMethod(false).GetMethodBody().
        return propInfo.GetValue(myTheme, null) as string[];
    }
 
    private void _SetThemeStyleSheets(string[] stylesheets)
    {
        PageTheme myTheme = _GetPageTheme();
 
        // myTheme.GetType is necessary (as opposed to typeof(PageTheme), 
        // because it is a runtime-defined type {ASP.ThemeName}
 
        // NOTE: this object is runtime created/defined as {ASP.ThemeName}, 
        // and LinkedStyleSheets only has a read-only accessor (get property). 
        // Using the following method I found that the storage field was 
        // in fact "__linkedStyleSheets" (double underscore)
        //FieldInfo[] fieldInfos = myTheme.GetType().GetFields(
        //    BindingFlags.GetField |
        //    BindingFlags.Instance |
        //    BindingFlags.NonPublic);
 
        FieldInfo fieldInfo = myTheme.GetType().GetField("__linkedStyleSheets",
            BindingFlags.GetField |
            BindingFlags.Instance |
            BindingFlags.NonPublic);
 
        fieldInfo.SetValue(myTheme, stylesheets);
        return;
    }
 
}

Open in new window