Saturday, June 12, 2010

CSS Registration and Rendering for SharePoint 2010 (including themes)

Updated 2011 december 20th

Topic :

In my previous post on the ms-rteStyle, the  ms-rteElement CSS classes and their role in the generation of the Styles and the Markup Styles menus items within the SharePoint 2010 Ribbon, I promised a real world example of the Wiki Page branding. I will provide it soon, but first of all I had to deeply explore how all was implemented in the new SharePoint 2010 version so this post will be a very technical review of the involved blocks. That way, I will be able to refer to the technical explanations of this post when I publish a real example of branding.

Technical review of the CSSLink , and  CssRegistration WebControls in SharePoint 2010 and their use for the SharePoint 2010 themes

To start from the beginning, I simply looked at the html source of a SharePoint 2010 wiki page created in a standard team site, and noticed this three link references:

   <link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/Themable/search.css?rev=Uoc0fsLIo87aYwT%2FGX5UPw%3D%3D"/>

   <link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/Themable/wiki.css"/>

   <link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/Themable/corev4.css?rev=iIikGkMuXBs8CWzKDAyjsQ%3D%3D"/>

Then, I decided to understand how they was generated by the product.

1 -The <SharePoint:CSSLink /> control - How does it work?

If you look in the v4.matser code you will find the control within the Head tag

     <SharePoint:CssLink runat="server" Version="4"/>

First, let us just examine the OnLoad method

method OnLoad

method SetDefaults
Check if it is the version 4 and choose between core.css corev4.css

method MakeCssUrl - Make the default CSS Url (primaryCssUrl)
If the variable cssFile is already affected, return it
else,
Check if there is customized CSS and return the url if yes.
If no NormalizeThemableCssFile (add themable in front of cssFile name if it is the corev4.css)
then MakeLayoutCSSUrl
At this time there is only two options (if you use native templates)
-->/_layouts/lcid/style/core.css
or
-->/_layouts/lcid/styles/Themable/corev4.css

Check if there is alternate CSS and if yes
cancel the default values
flag there is alternate css and register the value.

method SetupDialogCSS --> add dynamically CSS class to dialog and add a link to dlgframe.css



Conclusion, after the OnLoad method, the control will render only the link to

  • either  /_layouts/lcid/sytles/themable/corev4.css if you use v4.master and a site based on a native  SharePoint 2010 site definition.
  • or /_layouts/lcid/styles/core.css if you omit the Version property
  • or /_styles/something if you use customized css (ie stored in the database)
  • or /_layouts/lcid/styles/customFolder/customStyles.css if you use alternate CCS
  • or maybe the corev4.css of the theme if a theme is applied but I could not checked that...

Plus a link to dlgframe if you have open a SharePoint 2010 dialog.

Notice that this is a very bad idea to remove this control from a master page because
it sets programmatically the styles for the SharePoint 2010 dialogs.
it manages the version of the core.css file
it finds the customized styles if there is some
it switches to the alternate css if needed

Notice also that even if you use an alternate CSS and display a team site wiki page, the OOTB corev4.css will be loaded ANYWAY.
So, regarding the team site wiki pages the term alternate is WRONG...

For further information regarding this point you can read 2.8 - Second limitation of the team site wiki page in SharePoint 2010: it is very difficult to remove the OOTB RTE style

And much more as we are going to see with the new SharePoint 2010 themes. But before, let us finish with the two other links generated by the control:
So where does come the wki.css and the search.css references from?
They are rendered by the control in the Render method, based on the enumeration of the CssRegistrationCollection filled by at least a SharePoint.CssRegistration Web Control used in a declarative or imperative way.

2 - The <SharePoint:CssRegistration> control and the Microsoft.SharePoint.WebControls.CssRegistration.Register method

This control and this method are both linked to the <SharePoint:CSSLink> control, because they are adding links to a collection at the level of the site (CssRegistrationRecord) and the CSSLink control will enumerate this collection during the Render method to render all the links to css files that are registered within this collection.

 - The two link toward Themable/wiki.css and Themable/search.css are rendered by the CSSLink control using this way:

The Themable/wiki.css is registered at the wiki page template level in the wkpstd.aspx file located at 14/TEMPLATE/DocumentTemplates/wkpstd.aspx
You will find the instruction in the PlaceHolderAdditionalPageHead:

     <SharePoint:CssRegistration runat="server" Name="wiki.css" />

 - For the Themable/search.css reference it is much more tricky to find and explain:

If you examine the v4.master you will find a delegate control

     <SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox" Version="4" />


This delegate gives us the choice to call different kind of search box at the top of the page.
The link to the Themable/search.css is registered at the level of the web control called by the delegate control

There are three possible controls that can to be called by the delegate, they are registered in these three features:

  1. ContentLightup
  2. OSearchBasicFeature
  3. OSearchEnhancedFeature


This the ContentLightup feature has the 12.0.0.0 version ans the scope Farm

<Control
   Id="SmallSearchInputBox"

   Sequence="100
"
   ControlClass="Microsoft.SharePoint.WebControls.SearchArea
"
   ControlAssembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
>
</
Control>

and references the Microsoft.SharePoint.WebControls.SearchArea web control located in the Microsoft SharePoint dll


the OSearchBasicFeature feature has the 12.0.0.0 version and the scope WebApplication

<Control
  
Id="SmallSearchInputBox"

  
Sequence="50
"
  
ControlClass="Microsoft.SharePoint.Portal.WebControls.SearchBoxEx
"
  
ControlAssembly="Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
>

and references the Microssoft.SharePoint.Portal.WebControls.SearchBoxEx located in the Microsoft.Office.Server.Search dll


the OSearchEnhancedFeature has the version 14.0.0.0 and the scope WebApplication

<Control
  
Id="SmallSearchInputBox"

  
Sequence="25
"
  
ControlClass="Microsoft.SharePoint.Portal.WebControls.SearchBoxEx
"
  
ControlAssembly="Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
>

and also references the  the Microssoft.SharePoint.Portal.WebControls.SearchBoxEx located in the Microsoft.Office.Server.Search dll, but  its sequence number is lower and the properties of the feature element (SearchArea.xml) are different.

This is in this component (Microssoft.SharePoint.Portal.WebControls.SearchBoxEx) that the css link to the search.css is registered, in the OnPreRender method:

if (SPContext.Current.Web.UIVersion == 4)
{
   
CssRegistration.Register(
"Themable/search.css");
}

But how to know which control is actually called by the DelegateControl?

As you have noticed  for these three features, one has the scope Farm and the two other the scope WebApplication.
I have deployed and Entreprise version of SharePoint Server 2010 and  the THREE features are actually activated in my configuration:
I could checked it thanks to a providential application page coded by Slinger...

As the lowest sequence number delegate control wins, we have the Microssoft.SharePoint.Portal.WebControls.SearchBoxEx installed by the OSearchEnhancedFeature.

 

Now, we have to explain the difference between the standard styles and the themable styles because you have noticed that:

  1. in 14/TEMPLATE/LAYOUTS/1033/styles directory there is a folder called Themable where you can find files that are already present  in the styles folder
  2. the CSSLink control by default, references the corev4.css file that is located in the Themable folder
  3. the Microsoft developer that has coded the SearchBoxEx web control has choosen to reference the search.css in the Themable folder
  4. although the wiki.css in not registered with the Themable instruction, the rendered link references the wiki.css file located in the Themable folder

What all that does mean?
All this is linked to the new implementation of themes in SharePoint 2010. So, let us check the difference between the standard styles and the themable styles

3 - Specifying the themable styles

I have already talked a bit about SharePoint 2010 new themes in my previous post on the Managing the CSS styles for the SharePoint 2010 wiki pages and since the RTM delivery, things have been changed since the automatically generated themes files are now stored in another location than in the SharePoint 2010 Beta version.  

<link rel="stylesheet" type="text/css" href="/_catalogs/theme/Themed/9D9B7D55/corev4-8A0ABD2F.css?ctag=18"/>

<link rel="stylesheet" type="text/css" href="/_catalogs/theme/Themed/9D9B7D55/search-7E1AFF02.css?ctag=18"/>

When applying a theme in SharePoint 2010 the product takes the THEMABLE css files and generates automatically the new css files required for the theme and store them bellow the
 _catalog/theme/Themed/ virtual directory within the content database.

What is important to know is that you CAN specify which css file will be involved when applying a specific theme and which will be not, ie what file is themable and what is not.

In SharePoint 2010, the CSSRegistration web control has now  a new method CssRegistration.EnableCssTheming Property

Important: There is also a property called EnableTheming, so do not mistake EnableTheming that is inherited from System.Web.UI.Control for EnableCssTheming that is a new feature of SharePoint 2010 corresponding to the new SharePoint 2010 themes implementation.  



that can be used with the declarative way:

<SharePoint:CssRegistration runat="server" Name="customStyles.css" EnableCssTheming="true" />

 


 

"Fantastic!" you might think, but wait a minute, and keep focusing because its use and understanding is less than simple...

For instance, assume you allow yourself to perform quick tests of this control by customizing the template of the wiki pages (wkpstd.aspx) that is (I don't need to tell) not a thing to do in the real life.

So add a customStyle.css file in the lcid/Styles folder AND in the lcid/Styles/Themable folder
Then, place the previous declaration without the EnableCssTheming property within the template above the wiki.css registration and you will have this:

 

<SharePoint:CssRegistration runat="server" Name="customStyles.css" />

<SharePoint:CssRegistration runat="server" Name="wiki.css" />

now check the source html of the wiki page and surprise... 


<link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/customStyles.css?rev=D5q3ZhSBd%2FWysmMH%2BiJewA%3D%3D>
<link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/Themable/wiki.css?rev=9pXM9jgtUVYAHk21JOAbIw%3D%3D"/>

The exact same configuration and operation for the two files gives TWO different results. Why?

Especially, why, in the case of the wiki.css, although the EnableCssTheming is not set to true in the wkpstd.aspx template, the rendered link has the /themable/ path?
It is because we used the name of the file instead a path beginning by a '/'. The rule is the following:

If you pass a name of the following files as a parameter of the name property of the new SharePoint.CssRegistration web control, the generated link will ALWAYS reference the themable file:

  • blog.cs
  • calendarv4.css
  • corev4.css
  • datepickerv4.css
  • discthread.css
  • forms.css
  • groupboard.css
  • help.css
  • layouts.css
  • mblrte.css
  • menu.css
  • minimalv4.css
  • mws.css
  • owsnocr.css
  • survey.css
  • themev4.css
  • wiki.css
  • wpeditmodev4.css

These files references are neither in a CAML file nor in the Database, but hardcoded in the NormalizeThemableCssFile method within the CSSLink web control.

So if you want one of THESE native css files present in the themable folder NOT to be themable you must give the COMPLETE reference to the same file that is not in the themable folder:

<SharePoint:CssRegistration runat="server" Name="/_layouts/1033/styles/wiki.css" />

this DOES NOT work

<SharePoint:CssRegistration runat="server" Name="wiki.css" EnableCssTheming="false" />

Your file will remain themable anyway because it is one of the default themable css files!

 

On the other hand if you want either, one of the custom css files present in the themable folder, or one of the native files that are not in the default themable files list to be themable you must ,

either specify it explicitely

<SharePoint:CssRegistration runat="server" Name="custom.css" EnableCssTheming="true" />

or give a reference using a relative path starting from the Themable folder

<SharePoint:CssRegistration runat="server" Name="Themable/custom.css" />

or give a reference using a relative path starting fome the server

<SharePoint:CssRegistration runat="server" Name="/_layouts/1033/styles/Themable/custom.css" />

notice that if you don't give to the Name property a complete path but just the file name, and there is no corresponding file in the Themable folder, as SharePoint 2010 will check in the folder for this file, you will have an Exception.

Notice that you will have also an exception if the path is not just the file name but a real path and it does not start by a '/' (Except if the first word is Themable).

And finally if the path is well formed but is not good, you will not have any raised exception, but the page will not find your CSS file and you will not see your styles appear at the page displaying.

 


Now, we are going to examine the imperative side, it is no more simple...

 

If we look at the Microsoft documentation of the Microsoft.SharePoint.WebControls.CssRegsitration.Register method, we notice that we have the following overload
 

Public methodStatic member Register(String, Boolean) Registers the specified cascading style sheet (CSS) in master pages, content pages, or .ascx code pages, and specifies whether to reference the themed version of this CSS file if a theme is applied.

 

And we can see it with the Visual Studio intellisense

 

Important: this method has been completely rewritten for SharePoint 2010, and there is now an overload for EnableCssTheming. The parameter enableTheming that you can see on the screenshot showing Visual Studio Intellisense is corresponding to the EnableCssTheming property of the control that is a new feature of SharePoint 2010 for the SharePoint 2010 themes implementation. Do not mistake this parameter (EnableTheming) with the EnableTheming property of  CssRegistration that is inherited from System.Web.UI.Control

 

I know it is difficult to understand and I was puzzled myself so to conclude :

  1. Forget CssRegistration.EnableTheming, you don't need it, it is for the ASP .Net themes
  2. CssRegistration.EnableCssTheming and the boolean parameter enableTheming of the method CssRegistration.Register(String,Boolean) are the same exactly although the names are different.

 

 

So, our previous Microsoft developer when implementing  the Microssoft.SharePoint.Portal.WebControls.SearchBoxEx, had to specify the themable folder because the search.css is not themable by default (Although it is one of the native SharePoint 2010 css files present in the themable folder), but he (she) could have also written:

 

if (SPContext.Current.Web.UIVersion == 4)
{
    
CssRegistration.Register("search.css",true
);
}

 or

if (SPContext.Current.Web.UIVersion == 4)
{
    
CssRegistration.Register("search.css",true,"4"
);
}


For ending,

If you want to register a themable css file programmatically, consider overriding the OnInit method.

<script runat="server">
protected override void OnInit(EventArgs e)
{
   base.OnInit(e);
   CssRegistration.Register("wiki.css");
   CssRegistration.Register("Themable/customStyles.css");
}

To obtain themable references (You will notice that I have omited the Themable/ path for the wiki.css on purpose because here also, we can omit the path for the ccs files that are themable by default.)

<link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/Themable/wiki.css?rev=9pXM9jgtUVYAHk21JOAbIw%3D%3D"/>
 <link rel="stylesheet" type="text/css" href="/_layouts/1033/styles/Themable/customStyles.css?rev=D5q3ZhSBd%2FWysmMH%2BiJewA%3D%3D"/>


That can be used when applying a SharePoint 2010 theme.

<link rel="stylesheet" type="text/css" href="/_catalogs/theme/Themed/9D9B7D55/wiki-ECF524AA.css?ctag=24"/>
<link rel="stylesheet" type="text/css" href="/_catalogs/theme/Themed/9D9B7D55/customStyles-E81897D9.css?ctag=24"/>

Conclusion

If you want your custom CSS to be a part of a SharePoint 2010 theme, you must use the CssRegistration web control.
Never, ever remove the CSSLink control from a SharePoint 2010 master page.
One fantastic thing : If you add a themable css file reference programmatically to a site, you have not to re apply the theme. The css is automatically included within the theme references when refreshing the page.

This is some of my other posts on the topic:

--> Use a delegate control to reference a CSS at the wiki page level: Managing the CSS styles for the SharePoint 2010 wiki pages

--> To se the dynamic loading of the styles by debugging the SharePoint 2010 Ribbon and think about changing the CSS for the wiki pages: Customizing and branding the SharePoint 2010 wiki pages

2 comments:

Anonymous said...

Its good to know actually and it was interesting too.Thanks for ur info :)

Anders Rask said...

Apparently ?rev= is only appended if you place your CSS file under 1033 or similar language specific folder, and not in _Layouts/styles