Back to Cleverworkarounds mainpage
 

More SharePoint Branding - Customisation using JavaScript Part 3


Hey there. Welcome to part 3 of my series on SharePoint customisation using JavaScript and web parts.

So here is the lowdown so far. We are trying to find an effective, repeatable way to easily customise SharePoint form pages, so that we can hide fields or form elements when we need to. The goals were to:

  • Allow hidden fields based on identity
  • Avoid use of SharePoint Designer
  • Avoid customisations to the form pages that unghosted the pages from the site definition

So how have we progressed thus far?.

  • Part 1 of this series looked at how we can use JavaScript to deal with the common request of hiding form elements from the user in lists and document libraries.
  • Part 2 wrapped this JavaScript code into a web part which has been loaded into the SharePoint web part gallery.

So let’s knock the rest of this over and pick up right from we left off…

CleverWorkArounds Coffee requirement of this post depends on how much you hate JavaScript.

Metrosexual web developer    image

Socially inept technical guy    imageimageimage

[Quick Navigation: Part 1, Part 2, Part 4, Part 5 and Part 6]

Continue reading “More SharePoint Branding - Customisation using JavaScript Part 3″

No Tags



More SharePoint Branding - Customisation using JavaScript Part 2

Hi again.

JavaScript sucks! There I said it. Despite me hating it as a programming language, I can’t deny that in SharePoint, it does have its uses.

CleverWorkArounds Coffee requirement of this post depends on how much you hate JavaScript.

Metrosexual web developer    image
Socially inept technical guy    imageimageimage
Luddite IT manager                   imageimageimageimageimageimageimageimageimage 
(sorry … why are you here anyway?)

[Quick Navigation: Part 1, Part 3, Part 4, Part 5 and Part 6]

To quickly recap the first post of this series, we looked at how we can use JavaScript to deal with the common request of hiding form elements from the user in lists and document libraries. The technique demonstrated can be used for columns, buttons and whatever else you want. The method once debugged, is fairly easy to implement with SharePoint designer with and some cut and paste.

But there are several problems with the method that prevent it from getting a better CleverWorkaround rating than “Meh”. They include:

  • One size fits all, fields are hidden for all visitors irrespective of need.
  • You need to modify the page in SharePoint designer via cut and paste of JavaScript code
  • You need to modify auto-generated pages
  • You need to modify a page from its site definition
  • Insecure, relying on client side to hide content/controls is not a secure solution

Continue reading “More SharePoint Branding - Customisation using JavaScript Part 2″

No Tags



SharePoint Branding Part 7 -The ‘governance’ of it all..

Well, here we are! After delving into dark arts where everybody but metrosexual web designers fear to tread (HTML and CSS), we then delved into the areas that metrosexual web designers truly fear to tread (packaging, deployment and even some c# code!). Finally, we get to the area where everybody is interested until it happens to get in their way! (Ooh, I am a cynical old sod tonight).

That is Governance!

Continue reading “SharePoint Branding Part 7 -The ‘governance’ of it all..”

No Tags



SharePoint Branding Part 5 – Feature Improvements and Bugs

So, here we are at the fifth article in my series on SharePoint branding. By now, we have left all the master page stuff way behind, and we have created a custom feature to install our branding to a server.

To recap for those of you hitting this page first, I suggest you go back and read this series in order.

  • Part 1 dealt with the publishing feature, and some general masterpage/CSS concepts and some quirks (core.css and application.master) that have to be worked around.
  • Part 2 delved into the methods to work around the application.master and core.css issue
  • Part 3 delved further into the methods to work around the application.master and core.css issue and the option that solved a specific problem for me
  • Part 4 then changed tack and introduced how to package up your clever branding

Continue reading “SharePoint Branding Part 5 – Feature Improvements and Bugs”

No Tags



SharePoint Branding Part 4 – Packaging up your masterpiece into a Feature

Welcome to the fourth article in my series on SharePoint branding. Sorry for the time it’s taken to get this one out, but a certain game called “The Legend of Zelda:  Hourglass Phantom” on NDS got in the way. I finished it yesterday and only had to cheat via google once :-). Anyway it’s out of my system now so I can get back to this.

After 3 epic articles on all that painful CSS and master page stuff (part one, two and three), we now focus on what you have to do to get your branding masterpiece deployed to the SharePoint farm the clever way. In this next set of articles, we will look at where things should go, and then how to get it there the right way.

Continue reading “SharePoint Branding Part 4 – Packaging up your masterpiece into a Feature”

No Tags



Careful with pre-requisite SharePoint Features

After a web designer applied a new master page to a site, he killed the site. We saw these messages (debug logging was enabled on the site)

Server Error in ‘/’ Application.

——————————————————————————–

Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0030: Cannot convert type ‘Microsoft.SharePoint.WebControls.CssRegistration’ to ‘System.Web.UI.IAttributeAccessor’

Source Error:

Line 19: <link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/my.css” mce_href=”/sites/pc/Style%20Library/my.css”/>

Line 20: ” __designer:Values=”<P N=’InDesign’ T=’False’ /><P N=’ID’ T=’ctl01′ /><P N=’Page’ ID=’1′ /><P N=’TemplateControl’ ID=’2′ /><P N=’AppRelativeTemplateSourceDirectory’ R=’-1′ />”/>

Line 21:     <SharePoint:CssRegistration name=”<% $SPUrl:~SiteCollection/Style Library/~language/Core Styles/Band.css%>” runat=”server” __designer:Preview=”<link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/en-US/Core%20Styles/Band.css” mce_href=”/sites/pc/Style%20Library/en-US/Core%20Styles/Band.css”/>

Line 22: ” __designer:Values=”<P N=’Name’ Bound=’True’ T=’SPUrl:~SiteCollection/Style Library/~language/Core Styles/Band.css’ /><P N=’InDesign’ T=’False’ /><P N=’ID’ T=’ctl02′ /><P N=’Page’ ID=’1′ /><P N=’TemplateControl’ ID=’2′ /><P N=’AppRelativeTemplateSourceDirectory’ R=’-1′ />”/>

Line 23:     <SharePoint:CssRegistration name=”<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/controls.css %>” runat=”server” __designer:Preview=”<link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/en-US/Core%20Styles/controls.css” mce_href=”/sites/pc/Style%20Library/en-US/Core%20Styles/controls.css”/>

Source File: /_catalogs/masterpage/Mydefault.master Line: 21

Here’s a similar error I saw..

Server Error in ‘/’ Application.

——————————————————————————–

Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Type ‘Microsoft.SharePoint.WebControls.DelegateControl’ does not have a public property named ‘SearchBoxEx’.

Source Error:

Line 38:     <SharePoint:DelegateControl runat=”server”

Line 39:         ControlId=”SmallSearchInputBox” Visible=”False”>

Line 40:         <WpNs0:SearchBoxEx runat=”server” TitleLocIdNum=”0″ DropDownMode=”ShowDD” GoImageActiveUrlRTL=”/_layouts/images/goRTL.gif” TitleLocId=”Null” TextBeforeTextBox=”" ScopeDisplayGroupName=”Search Dropdown” AdvancedSearchPageURL=”/searchcenter/Pages/Advanced.aspx” DescriptionLocIdNum=”0″ AppQueryTerms=”" FrameType=”None” QueryPromptString=”" GoImageActiveUrl=”/_layouts/images/gosearch.gif” SuppressWebPartChrome=”False” GoImageUrlRTL=”/_layouts/images/goRTL.gif” ShouldTakeFocusIfEmpty=”False” GoImageUrl=”/_layouts/images/gosearch.gif” UseSiteDefaults=”True” DropDownModeEx=”ShowDD” DescriptionLocId=”Null” AppQueryTermsLabel=”" ExportMode=”All” ChromeType=”None” ShowAdvancedSearch=”True” TextBeforeDropDown=”" SearchResultPageURL=”/searchcenter/Pages/Results.aspx” RegisterStyles=”True”>

Line 41:         <input runat=”server” EnableViewState=”False” value=”http://asite” type=”hidden”>

Line 42:         </input>

Source File: /default.aspx Line: 40

And one more for good measure with the clincher..(if you check carefully it actually has a meaningful error message)

Server Error in ‘/’ Application.

——————————————————————————–

Compilation Error

Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0234: The type or namespace name ‘Publishing’ does not exist in the namespace ‘Microsoft.SharePoint’ (are you missing an assembly reference?)

Source Error:

[No relevant source lines]

Source File: c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\36831729\da3a8eb\App_Web_999d82a0-fd08-4618-a707-bd83850f7eb6_-1117136529.nygwjb5c.0.cs Line: 1183

The root cause of all of three issues is that the new master page applied was built from the default master page (DEFAULT.MASTER - ie the designer took a copy of it and worked from that copy). However, these sites were originally built with the “SharePoint Publishing Infrastructure” site collection feature enabled. If you examine the default.master and compare with a publishing master page like blueglass.master you will see several differences.

Default.master

<%@ Register Tagprefix=”SharePoint” Namespace=”Microsoft.SharePoint.WebControls” [snip] <%@ Register Tagprefix=”WebPartPages” Namespace=”Microsoft.SharePoint.WebPartPages” [snip]] <%@ Register TagPrefix=”wssuc” TagName=”Welcome” [snip] <%@ Register TagPrefix=”wssuc” TagName=”DesignModeConsole” [snip]

Now compare with BlueGlassBand.master and note extra assembly declarations in bold.

<%@ Register Tagprefix=”SPSWC” Namespace=”Microsoft.SharePoint.Portal.WebControls” Assembly=”Microsoft.SharePoint.Portal, [snip]
<%@ Register Tagprefix=”SharePoint” Namespace=”Microsoft.SharePoint.WebControls” [snip]
<%@ Register Tagprefix=”WebPartPages” Namespace=”Microsoft.SharePoint.WebPartPages” [snip]
<%@ Register Tagprefix=”PublishingWebControls” Namespace=”Microsoft.SharePoint.Publishing.WebControls” [snip]
<%@ Register Tagprefix=”PublishingNavigation” Namespace=”Microsoft.SharePoint.Publishing.Navigation” [snip]
<%@ Register TagPrefix=”wssuc” TagName=”Welcome” [snip]
<%@ Register TagPrefix=”wssuc” TagName=”DesignModeConsole” [snip]
<%@ Register TagPrefix=”PublishingVariations” TagName=”VariationsLabelMenu” [snip]
<%@ Register Tagprefix=”PublishingConsole” TagName=”Console” [snip]
<%@ Register TagPrefix=”PublishingSiteAction” TagName=”SiteActionMenu” [snip]

I added these additional declarations to my customised master page and lo and behold, problems gone

No Tags



SharePoint Branding - How CSS works with master pages – Part 3

Welcome to the third article (or is it a manifesto?) in my series on SharePoint branding. In this article, we continue examining methods to incorporate CSS files into master pages for clever branding. In my first article of this topic, I discussed what I think is the main issue with SharePoint branding - APPLICATION.MASTER and CORE.CSS. The previous article to this one, examined 5 methods to deal with the trial and tribulations of APPLICATION.MASTER and CORE.CSS behavior. So, to recap where we got to, let’s re-examine the original scenario and then look at the summary of the 5 different several methods with their relative merits and issues.

The Scenario

Like many organizations, my client had an existing corporate branding standard that was used in a non SharePoint environment and naturally enough, they wanted their SharePoint site to look like this branding. This was for a fully featured intranet/extranet that utilized most of the MOSS2007 features such as

  • Document collaboration
  • Infopath Forms Services
  • Workflow
  • Enterprise Search
  • Excel services
  • Business Data Catalog
  • Custom web parts
  • Event Handlers

It was *not* a public site at all.

Initial investigation soon concluded that we would need a custom master page. DEFAULT.MASTER didn’t quite have the design flexibility that was required. In fact the branding requirements were actually closer to some of the built in master pages such as BLUEGLASS.MASTER, since this was for intranet purposes, particularly collaborative document management, those master pages are unsuitable.

Other major requirements included mandatory consistency of branding across the entire farm. This meant that we had to deal with the APPLICATION.MASTER issue. Additionally, different semi-autonomous divisions within the client’s organisation wanted to be able to modify the corporate brand in accordance with existing branding policy (mainly colours/skinning) while maintaining the existing structural look and feel.

Additionally, as well as the corporate branding, there was another, very different branding which was used as part of a communications plan for some organizational change stuff. This had a deliberately different look to the rest of the site, yet the web designer had been clever when this design was created. They were able to completely rebrand the look and feel of the additional branding just through additional CSS and not wholesale HTML structural changes.

So, really, we had two general classes of sites. ‘Standard’ corporate sites and the custom branded ‘Organisational Change’ site.

The type of MOSS environment this was to be applied to was a medium to large SharePoint farm with three web front end (WFE) servers, and there were several SharePoint web applications and site collections in the farm that needed this branding. Further down the track, there was to be other SharePoint farms in different offices around the world with localized language requirements.

The final requirement (the one that complicated things) was that many of the CORE.CSS styles needed to be overridden to ensure the branding was correct.

Summary of CSS methods

Method Advantages Disadvantages
SharePoint:CSSRegistration - Easy to implement - Does not overrides core.css
- Does not work with _layout pages
Master Page Settings - Easy to implement
- Overrides core.css
- Works on _layout pages
- Can only be used once
- Has to be set up for each site
<link> method - Set in master page once
- Overrides core.css
- Precludes “Master Page Settings” CSS override
- Does not work with _layout pages
Michael’s webcontrol - Set in master page once
- Overrides core.css
- Works nicely with “Master Page Settings” CSS override
- Does not work with _layout pages
- core.css as the first CSS can be problematic
My webcontrol - Set in master page once
- Overrides core.css
- Works nicely with “Master Page Settings” CSS override
- core.css is not the first stylesheet in the list
- allows choice as to what css overrides core.css
- Does not work with _layout pages

Now for many SharePoint logical architectures, these methods will likely work well. Unfortunately in my situation each had enough drawbacks that I kept looking. So next stop: SharePoint Themes.

Over-riding CSS – SharePoint Themes

In my humble opinion, when you examine themes, it smells a little like legacy WSS/SharePoint 2 functionality carried over and now adds to confusion rather than clarifies. This is purely a hunch of course, but given the way themes have to be installed, and their scope across the farm, suggests to me that it may become a legacy feature going forward.

Why do I think this? Well, the official purpose a SharePoint theme is for ’skinning’ a site, but at the end of the day, a theme is just another CSS file, only implemented a different way. Being CSS, you can define any style you want here, not just the ones related to colour. Furthermore, the styles defined in themes can be used in any other other CSS files too.

Okay, so it is essentially another form of CSS file… then what is the difference between this and the other methods CSS I have outlined?

Well, for a start, theme CSS files live in a sub-folder of on the server:

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES

So, this is a location on the web front end server/servers, whereas with the other methods, the CSS files reside inside a document library of a site collection. I believe that document library is a better choice because you have all those niceties like versioning, approvals and recycle bin, etc. If you have a farm of WFE servers, you would have to add your theme to each server and hope no mistake was made.

On top of being in every WFE server folder, just making a CSS file and dropping it in here is not enough either. Examining one of the pre-supplied themes shows that a theme consists of CSS files, an INF file, and of course, the images referred to by the styles. The two CSS files are called THEME.CSS and MOSSEXTENSION.CSS. (When you apply a theme to a site, MOSSextension.css is appended to the bottom of your theme.css)

The INF file is always the name of the theme folder, eg

<path to sharepoint>\12\TEMPLATE\THEMES\CITRUS contains CITRUS.INF

So you create a folder, add the CSS, INF and images, and finally, you then have to tell SharePoint about it. This is done by modifying a single XML file called SPTHEMES.XML.

SPTHEMES.XML can be found in:

C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033

A typical entry will look like:

<Templates>
    <TemplateID>PimpMySharePoint</TemplateID>
    <DisplayName>Pimp me</DisplayName>
    <Description>A pimped sharepoint</Description>
    <Thumbnail>images/thpimp.gif</Thumbnail>
    <Preview>images/thvpimp.gif</Preview>
</templates> 

So let’s look at an example.

I have taken a copy of the CLASSIC folder under THEMES, info a folder called PIMPMySharePoint. I’ve then renamed CLASSIC.INF to PIMPMYSHAREPOINT.INF and added this theme to SPTHEMES.XML.

I then run IISRESET and open up my site collection. Go to Site Actions->Site Settings and choose “Site Theme”

Now you should see your “Pimp SharePoint” theme listed

Click apply and re-examine the page. You will see that the look and feel of the site will have changed.

Now examine the HTML source in the browser. You will see something like

<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/controls.css?rev=EhwiQKSLiI%2F4dGDs6DyUdQ%3D%3D”/>
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/HtmlEditorCustomStyles.css?rev=8SKxtNx33FmoDhbbfB27UA%3D%3D”/>
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/HtmlEditorTableFormats.css?rev=guYGdUBUxQit03E2jhSdvA%3D%3D”/>
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/core.css?rev=5msmprmeONfN6lJ3wtbAlA%3D%3D”/>
<link rel=”stylesheet” type=”text/css” id=”onetidThemeCSS” href=”/sites/ft1/_themes/PimpSharePoint/Pimp1011-65001.css?rev=12%2E0%2E0%2E6007″/>

Note that the theme (in bold) is rendered after core.css.

How did this happen?

You should already be familiar with SharePoint:CssLink and SharePoint:CssRegistration webcontrols via my previous articles. Behind the scenes to all of this, the theme is rendered via an additional control called the <Sharepoint:Theme> in the master page. Here is DEFAULT.MASTER source code that produced the above output

<Title ID=onetidTitle><asp:ContentPlaceHolder id=PlaceHolderPageTitle runat=”server”/></Title>
<SharePoint:CssLink runat=”server”/>
<SharePoint:Theme runat=”server”/> 

If you look carefully at the above source code, you will see that the only reason that the theme has overriding CORE.CSS is because the SharePoint:Theme control is listed after Sharepoint:CSS. If you reverse the order of the two controls, as expected the order of the theme is changed. In the example below, I took a copy of DEFAULT.MASTER and made the following modification:

<Title ID=onetidTitle><asp:ContentPlaceHolder id=PlaceHolderPageTitle runat=”server”/></Title>
<SharePoint:Theme runat=”server”/>
<SharePoint:CssLink runat=”server”/>

and the resulting HTML is now reversed with CORE.CSS once again last.

<link rel=”stylesheet” type=”text/css” id=”onetidThemeCSS” href=”/sites/ft1/_themes/PimpSharePoint/Pimp1011-65001.css?rev=12%2E0%2E0%2E6007″/>
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/controls.css?rev=EhwiQKSLiI%2F4dGDs6DyUdQ%3D%3D” />
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/HtmlEditorCustomStyles.css?rev=8SKxtNx33FmoDhbbfB27UA%3D%3D” />
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/HtmlEditorTableFormats.css?rev=guYGdUBUxQit03E2jhSdvA%3D%3D” />
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/core.css?rev=5msmprmeONfN6lJ3wtbAlA%3D%3D” />

Thus, although you will read that themes are used to say, “re-skin the layout of a site”, in reality, it is the order of the application of CSS files that determine what parts of a site a theme will modify. Put in a different way, you add whatever you like to the theme CSS files and it will act like any other CSS, except it gets rendered last by default.

Heather notes that themes have the same benefit as using “Master Page Settings” to override CORE.CSS. That is, they also apply to _layouts pages and affect APPLICATION.MASTER. The only reason that they work here is because the APPLICATION.MASTER master page used for _layout pages has the SharePoint: Theme webcontrol in its source code.

A gotcha with this method is that themes are per farm. Since they reside on the web front end server, my “Pimp Sharepoint” theme is available to any site in the farm. What’s more, if I modify the theme here, all sites are modified. This can be good but is equally going to catch you out as your SharePoint farm grows.

Another gotcha! Do not for a second assume that the SharePoint:Theme control is always included in master pages because it is not! Go and check the master pages that are installed by the “Office SharePoint Server Publishing Infrastructure” feature and you will see that none of them use the SharePoint:Theme webcontrol. Therefore, no matter what you put as your theme for sites based on publishing master pages, only the _layout pages (based on APPLICATION.MASTER) are affected by the theme CSS. (This to me reinforces my belief that themes are a legacy technology.)

Another gotcha! You will not like themes if you have a lot of sub-sites because you have to apply it at the site level for each site. Unlike the other methods described thus far, this method is not inheritable to sub-sites.

Yet another issue that makes this method a low cleverworkarounds rating, is that themes have to be installed on the web front end servers. In a large scale farm, there may be several WFE servers that need this set. There is no version control, version history, recycle bin, publishing approvals, and as a developer it means you have to deal with anal SharePoint infrastructure or governance Nazis who will not even talk to you unless you have packaged your work up as a solution.

Cleverworkaround Rating: Sucky

Overriding CSS – Master Page Settings with @import

This is a method that I considered but did not test, although I am sure that it will work (so I would be happy to hear from anyone who did). It actually needs to be used in combination with the “master page settings” method that I described in article 2. The idea here is based around strict naming conventions for CSS files.

Now remember my original scenario, I have a master page, and a corporate brand CSS that needs to override CORE.CSS (CSS number #1). But then I have additional CSS files that override the corporate brand CSS file depending on the site. Using the master page settings to specify a CSS file only deals with CSS number 1.

But my idea here is that the CSS to be specified in Master Page Settings (CSS number 1) , refers to one of more additional CSS via the @import directive. The names are strictly defined, so for example:

@import url(brandingoverridemintyfresh.css);

@import url(brandingoverrideorgchange.css);

So now, you have two extra CSS ‘placeholders’. If they do not exist in the site collection, they will not be used. But if you put a CSS file into the site collection, and give it one of the above names, you should in theory get the additional styles required.

This method seems relatively simple in the sense that it is all done in the CSS files, and the SharePoint GUI. However, since by default the CSS files reside in the site collection style library, adding or removing CSS files affect the entire site collection. This behavior can probably overridden with hard-coded or relative URL’s but it will not be great. Hard-coding anything is “not clever” for scalability and flexibility, and relative URL’s are difficult because site collections are not necessarily top level sites.

In addition, your CSS file can get ugly, with lots of @import references to files that do not exist which will confuse things later if governance around this is not well handled.

I won’t assign this a rating, given that I didn’t test it. But I can see it would have its uses in some circumstances. If someone wants to experiment with this I’m happy to link you, or add to this article.

My solution

Now despite the fact that I’ve in effect bagged themes earlier, the actual styles defined in the themes are some of the ones you are likely to be interested in, when performing a branding exercise. It is this fact that led me to my final solution that for me, had the best clever rating of all.

So let’s now examine our matrix so far with the addition of the themes method.

Method Advantages Disadvantages
SharePoint:CSSRegistration - Easy to implement - Does not override core.css
- Does not work with _layout pages
Master Page Settings - Easy to implement
- Overrides core.css
- Works on _layout pages
- Can only be used once
- Has to be set up for each site
<link> method - Set in master page once
- Overrides core.css
- Precludes “Master Page Settings” CSS override
- Does not work with _layout pages
Michael’s webcontrol - Set in master page once
- Overrides core.css
- Works nicely with “Master Page Settings” CSS override
- Does not work with _layout pages
- core.css as the first CSS can be problematic
My webcontrol - Set in master page once
- Overrides core.css
- Works nicely with “Master Page Settings” CSS override
- core.css is not the first stylesheet in the list
- allows choice as to what css overrides core.css
- Does not work with _layout pages
Custom Themes - Easy to implement (GUI set)
- Overrides core.css
- Works on _layout pages
- Modifying the theme modifies all sites using it
- Not inherited - has to be manually set for all sites
- Installing and updating themes require farm administrator and manual configuration of WFE servers
- Not all master pages will obey the theme

Over-riding CSS - The hybrid!

Now remember my original scenario, I have a master page, and a corporate brand CSS that needs to override CORE.CSS (CSS number 1). But then I have additional CSS files (let’s collectively call them CSS number 2), that override the corporate brand CSS file depending on the site. CSS number 2 assumes that CSS number 1 is also referenced. This keeps CSS number 2 smaller and more manageable. But the disadvantage is that as discussed, using the master page settings to specify a CSS file can only be used once and therefore only deals with CSS number 1.

But…what if we took all of the bits that needed to be overridden CORE.CSS and moved them to CSS number 2? Then CSS number 1 is left with styles that CORE.CSS does not interfere with.

CSS number 2 (remember there are potentially many of these) is a little bigger now, as it has some additional styles since now it has to deal with any CORE.CSS interference, however it is still relatively maintainable.

So then, we can do this… (…drumroll)

Have the generic branding (CSS number 1) added to the master page using the SharePoint:CSSRegistration method. Then any CSS number 2, can be specified by the ‘master page settings’ method.

So to illustrate, let’s take a look at the source code to our branded master page.

<SharePoint:CssLink runat=”server”/>
 <SharePoint:CssRegistration name=”<% $SPUrl:~SiteCollection/Style Library/~language/Core Styles/Band.css%>” runat=”server”/>
  <SharePoint:CssRegistration name=”<% $SPUrl:~sitecollection/Style Library/~language/Core Styles/controls.css %>” runat=”server”/>
 <SharePoint:CssRegistration name=”<% $SPUrl:~sitecollection/Style Library/zMyDefaultBrand.css %>” runat=”server”/>
  <SharePoint:Theme runat=”server”/> 

So, looking at this code, you can see that we are using SharePoint:CssRegistration, to specify a CSS file called zMyDefaultBrand.css. Remember why I prepended it with a z? It’s because SharePoint:CssLink control renders CSS files in alphabetical order it will be rendered last by the CSSLink webcontrol, except for CORE.CSS of course.

You can also see that I left the SharePoint:Theme control in so it can be used if required.

So, since we have moved all the CORE.CSS overrides to CSS number 2, we have a default CSS file called MyTheme.css. This now goes hand in hand with zMyDefaultBrand.css and is set set via the “master page settings” screen.

So the rendered HTML code combines to this:

<link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/en-US/Core%20Styles/Band.css” mce_href=”/sites/pc/Style%20Library/en-US/Core%20Styles/Band.css”/>
<link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/en-US/Core%20Styles/controls.css” mce_href=”/sites/pc/Style%20Library/en-US/Core%20Styles/controls.css”/>
<link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/zMyDefaultBrand.css” mce_href=”/sites/pc/Style%20Library/zMyDefaultBrand.css”/>
<link rel=”stylesheet” type=”text/css” href=”/sites/pc/_styles/core.css” mce_href=”/sites/pc/_styles/core.css”/>
<link rel=”stylesheet” type=”text/css” href=”/sites/pc/Style%20Library/MyTheme.css” mce_href=”/sites/pc/Style%20Library/MyTheme.css”/> 

Let’s look at the result and compare with our requirements. As you can see, CORE.CSS still beats zMyDefaultBrand.css but it is subsequently beaten by MyTheme.css, so we can override any CORE.CSS quirks.

Since MyTheme.CSS contains all of the look and feel styles that are usually defined in the SharePoint themes and CORE.CSS, the _layouts pages based on APPLICATION.MASTER get overridden nicely. By splitting the CSS we are able to define the global style in zMyDefault.css and the *default* CORE.CSS override in MyTheme.CSS

Since we are using master page override method, this is set on a per site basis and is inheritable from a parent site. Now our web designers can work their CSS magic to make additional MyTheme.css type files to offer flexible branding options such as MyThemeMintyFresh.CSS or MyThemeCorporateBrandB.CSS. Web administrators can pick the CSS file they want to use on a site by site basis giving complete flexibility.

Wohoo!

Cleverworkaround rating: Nice

Summary

So here is the final version of my table..

Method Advantages Disadvantages
SharePoint:CSSRegistration - Easy to implement - Does not override core.css
- Does not work with _layout pages
Master Page Settings - Easy to implement
- Overrides core.css
- Works on _layout pages
- Can only be used once
- Has to be set up for each site
<link> method - Set in master page once
- Overrides core.css
- Precludes “Master Page Settings” CSS override
- Does not work with _layout pages
Michael’s webcontrol - Set in master page once
- Overrides core.css
- Works nicely with “Master Page Settings” CSS override
- Does not work with _layout pages
- core.css as the first CSS can be problematic
My webcontrol - Set in master page once
- Overrides core.css
- Works nicely with “Master Page Settings” CSS override
- core.css is not the first stylesheet in the list
- allows choice as to what css overrides core.css
- Does not work with _layout pages
Custom Themes - Easy to implement (GUI set)
- Overrides core.css
- Works on _layout pages
- Modifying the theme modifies all sites using it
- Not inherited - has to be manually set for all sites
- Installing and updating themes require farm administrator and manual configuration of WFE servers
- Not all master pages will obey the theme
My Hybrid Method - Easy to implement (GUI set)
- Overrides core.css
- Works on _layout pages
- master page setting is always specified

Next steps

I am a two finger typist, so after 3 articles you would think we are done. But nooooo, we still haven’t solved all of the issues. Next stop, we examine how to deploy this to the farm set-up in a nice, easy to maintain format. So we do some work on features, solutions, quirks (yeah there are quirks) and governance around it all.

No Tags



SharePoint Branding - How CSS works with master pages - Part 2

Jeez if I had realised how long it would take to write these damn articles, I probably wouldn’t have started! In my first article of this topic, I discussed the theory behind master pages, the publishing feature, and what I think is the main issue with SharePoint branding - APPLICATION.MASTER and CORE.CSS. In this article I will now list a branding scenario that I had to deal with, and the various options you can use to deal with the challenges of APPLICATION.MASTER and CORE.CSS

The Scenario

Like many organizations, my client had an existing corporate branding standard that was used in a non SharePoint environment and naturally enough, they wanted their SharePoint site to look like this branding.

This was for a fully featured intranet/extranet that utilized most of the MOSS2007 features such as

  • Document collaboration
  • Infopath Forms Services
  • Workflow
  • Enterprise Search
  • Excel services
  • Business Data Catalog
  • Custom web parts
  • Event Handlers

It was *not* a public site at all.

Initial investigation soon concluded that we would need a custom master page. DEFAULT.MASTER didn’t quite have the design flexibility that was required. In fact the branding requirements were actually closer to some of the built in master pages such as BLUEGLASS.MASTER, since this was for intranet purposes, particularly collaborative document management, those master pages are unsuitable. (I will explain why soon).

Other major requirements included mandatory consistency of branding across the entire farm. This meant that we had to deal with the APPLICATION.MASTER issue as described in my last post. Additionally, different semi-autonomous divisions within the client’s organisation wanted to be able to modify the corporate brand in accordance with existing branding policy (mainly colours/skinning) while maintaining the existing structural look and feel.

Additionally, as well as the corporate branding, there was another, very different branding which was used as part of a communications plan for some organizational change stuff. This had a deliberately different look to the rest of the site, yet the web designer had been clever when this design was created. They were able to completely rebrand the look and feel of the additional branding just through additional CSS and not wholesale HTML structural changes.

So, really, we had two general classes of sites. ‘Standard’ corporate sites and the custom branded ‘Organisational Change’ site.

 

The type of MOSS environment this was to be applied to was a medium to large SharePoint farm with three web front end (WFE) servers, and there were several SharePoint web applications and site collections in the farm that needed this branding. Further down the track, there was to be other SharePoint farms in different offices around the world with localized language requirements.

The final requirement (the one that complicated things) was that many of the CORE.CSS styles needed to be overridden to ensure the branding was correct.

The Custom Master Page

The first decision to make is whether to stick to just CSS modifications to an existing master page, or to create a new master page. This post is based around a new master page, however the CSS methods I outline in this post are equally valid when using, say, DEFAULT.MASTER or one of the publishing master pages like BLUEBAND.MASTER.

So since we knew we had to use a custom master page, we had 3 choices in creating a new master page.

  • Make a copy of DEFAULT.MASTER and use that
  • Start with a completely blank master page
  • Make a copy of one of the publishing master pages like BLACKBAND.MASTER

I’ll actually deal with the third option first because we initially used it and then discounted it.

As previously mentioned, in our case BLUEGLASS.MASTER was the closest of the built in master pages to our branding needs but in the end we did not use it. Publishing master pages are actually somewhat simpler than the default.master page. Some web controls/placeholders have been modified/removed from publishing master pages, and if you use them for say, a document collaboration site, you will find quirks like:

  • Missing breadcrumb navigation in document libraries when browsing subfolders
  • Missing recycle bin link
  • Different navigational structure
  • Tree-view not being rendered despite being selected
  • Themes are ignored (I discuss this in detail in part 3)

Furthermore, I actually read not so long ago that it was recommended that these pages be generally used for internet facing sites which by definition tend to be publishing sites. (I’m trying to find the reference and as soon as I locate it I’ll paste here), but Tyler’s post offers some hints where he talks of custom CSS and navigation out of the box.

A blank master page is potentially a great option, either the MSDN one that everyone seems to hate or Heather’s, that the general population seems to like. Ultimately flexibility, of course, as it means that you can code up the look and feel from scratch. Unless you are a world class web designer and have a great understanding of ASP.NET, it may not be worth the time and budget (especially for an internal facing site).

So, we chose to simply make a copy of default.master because we actually did not have to change that much to achieve our ends. Yes it is complex and fiddly, but it is the out of the box master page that works with SharePoint, so using it as a base is a pretty safe bet. The main issue you need to watch out for when doing this, is related to the publishing feature.

So, for the purposes of this article, our new master page will be referred to as PIMPMYSHAREPOINT.MASTER – and we have to get our custom CSS styles into this.

Over-riding CSS – SharePoint:CSSRegistration

We took a look at SharePoint:CssRegistration and its brother SharePoint:CssLink in part 1, but I think it’s worth a recap.

SharePoint:CssRegistration defines a CSS file and Sharepoint:CssLink is the control that actually renders the SharePoint:CssRegistration styles as well as CORE.CSS.

<head runat=”server”>
[snip]
<Sharepoint:CssLink runat=”server” /
<!–Styles used for positioning, font and spacing definitions–>
<SharePoint:CssRegistration name=”<% $SPUrl:~SiteCollection/Style Library/pimpmysharepoint.css%>” runat=”server”/>
[snip]
</head>

And the result is…

<head>
[snip]
<link rel=”stylesheet” type=”text/css” href=”/sites/nopub/Style%20Library/pimpmysharepoint.css” mce_href=”/sites/nopub/Style%20Library/pimpmysharepoint.css”/>
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/core.css” mce_href=”/_layouts/1033/styles/core.css”/>
[snip]
</head>

As discussed in part 1, CORE.CSS, has been rendered, despite the fact that it is not explicitly defined. What’s more, CORE.CSS is always listed last.

Ah! But remember our requirement above? Our custom styles need to override styles in CORE.CSS! GONG! This isn’t going to do it for us.

Cleverworkaround Rating: Useless for me

Over-riding CSS – Master Page Settings

So we look at the next most obvious way to defeat this CORE.CSS issue. On a MOSS07 site with the “Office SharePoint Server Publishing Infrastructure” site collection feature enabled, we have the means to add a custom CSS to a master page via the GUI. It can be found in Site Settings on any site. Navigate to look and feel and choose “Master Page”.

Scroll to the bottom of this page and you will see the CSS override settings.

From here, you can choose a custom CSS file to use. In this example we have chosen pimpmysharepoint.css which was uploaded to the style library for this site collection. Let’s examine the HTML output once pimpmysharepoint.css has been selected.

<link rel=”stylesheet” type=”text/css” href=”/_styles/core.css” mce_href=”/_styles/core.css”/>
<link rel=”stylesheet” type=”text/css” href=”/Style%20Library/PimpMySharePoint.css” mce_href=”/Style%20Library/PimpMySharePoint.css”/>

Aha! We have overridden CORE.CSS – nice! Given that we have not modified the master page itself, we can conclude that SharePoint:CssLink will render the “alternate CSS URL” last. In addition, we have solved the APPLICATION.MASTER problem. Hands up who can tell me why ? :-) The reason is that APPLICATION.MASTER uses SharePoint:CssLink as well, so it will render this CSS in _layout pages derived from that master page.

Furthermore, we did it with no coding or custom work, and it can be inherited or forced out to all subsites from this one. WOHOO!

So? Have we found our clever workaround? No we have NOT. DOH! We have a workaround, but I do not believe that it’s clever yet!

Remember my requirements. We had a corporate brand that required CORE.CSS override for a few styles. In addition, we have the ‘organizational change’ branding CSS that overrides the corporate branding CSS. In addition, even within corporate branding we had CSS overrides for individual departments too.

So what is our problem then?

Using this method, we can only override once! Once you set this alternate CSS, that’s it. Thus, if I was to use this method, I would have to maintain several large custom CSS files, one for each branding scenario. Given that 80% of the actual styles are consistent between them, I prefer a method where the common stuff is kept common, rather than risk being fragmented over time with changes to one of the CSS files not being propagated to others.

I’m sure many of you would be okay with this, and for certain clients, I would be too. However, call me anal if you want but I wanted to find a better way.

CleverWorkaround Rating: Close, but no cigar!

Over-Riding CSS – Static CSS Link

Now, given that SharePoint:CssLink control renders stylesheet links at runtime, what is stopping us simply adding a static CSS link in the master page? The source code below illustrates the idea.

<head runat=”server”>
[snip]
<Sharepoint:CssLink runat=”server” /
<!–Styles used for positioning, font and spacing definitions–>
<SharePoint:CssRegistration name=”<% $SPUrl:~SiteCollection/Style Library/pimpmysharepoint.css%>” runat=”server”/>
<link rel=”stylesheet” type=”text/css” href=”/Style Library/anothercss.css”/>
[snip]
</head>

This works on the premise that 80% of your branding (the stuff that CORE.CSS doesn’t screw with) is in PIMPMYSHAREPOINT.CSS. The other 20% that needs to override CORE.CSS is in ANOTHERCSS.CSS.

So, now I have embedded a static link into the master page. Before we go on to assess its cleverness, can you see my mistake?

Imagine, that you have 3 site collections named:

That static link, will always try and use the style library for the top site collection, even for the bottom two site collections. But what if the users do not have permission to the top site collection? Will the CSS render? Probably not as access to it would be denied.

Here is the adjusted source to fix this – using a token to render the correct site collection URL.

<head runat=”server”>
[snip]
<Sharepoint:CssLink runat=”server” /
<!–Styles used for positioning, font and spacing definitions–>
<SharePoint:CssRegistration name=”<% $SPUrl:~SiteCollection/Style Library/pimpmysharepoint.css%>” runat=”server”/>
<link rel=”stylesheet” type=”text/css” href=”<% $SPUrl:~SiteCollection/Style Library/anothercss.css%”/>
[snip]
</head>
>

See what I have done (in bold)? I have placed the rendered link into the master page source. I have used the $SPURL:~SiteCollection token though which at runtime gets replaced with the path to the site collection. (In the example below the site collection was called “/sites/nopub”).

So let’s examine the HTML output of this.

<head>
[snip]
<link rel=”stylesheet” type=”text/css” href=”/sites/nopub/Style%20Library/pimpmysharepoint.css” mce_href=”/sites/nopub/Style%20Library/pimpmysharepoint.css”/>
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/core.css” mce_href=”/_layouts/1033/styles/core.css”/>
<link rel=”stylesheet” type=”text/css” href=”/sites/nopub/Style%20Library/anothercss.css” mce_href=”/sites/nopub/Style%20Library/anothercss.css”/>
[snip]
</head>

Wohoo! We have our custom styles after CORE.CSS. What’s more, we can add as many <link> entries as we like here. Although not shown above, I could have one <link> with the 80% of common styles and another <link> with the 20% of custom ones.

So have we found our branding utopia? No – hell no!

One of the disadvantages with this method is that if your <link> is placed AFTER SharePoint:CssLink, then it will also trump your “alternate CSS URL” setting described in the “master page setting” method. This is because the alternate CSS URL is rendered by SharePoint:CssLink. Placing your static link before SharePoint:CssLink is utterly pointless, because all of the CSS files specified by SharePoint:CssRegistration will trump the <link> entry. The whole point here was to override CORE.CSS.

If that wasn’t bad enough, the clincher is that _layout pages, based on APPLICATION.MASTER master page, will not have this static link anyway. Therefore, your branding is inconsistent for _layout pages and in fact is likely WORSE because it will apply the 20% customizations of ANOTHERCSS.CSS but the other 80% of PIMPMYSHAREPOINT.CSS common styles will be missing.

CleverWorkaround Rating: Pretty damn crappy actually !

So, what can we try next?

Over-riding CSS – Mike’s method

Now this method I was very, very impressed with (and cursed that I did not think of it myself). Mike came up with a novel way to solve the CORE.CSS problem. He created his own asp.net control that REPLACES SharePoint:CssLink. He has inherited the CSSLink class and modified the rendered output to move CORE.CSS from last to first. Ingenious!

So, to implement this, you need to compile it to a DLL in visual studio. You need to copy the DLL into the global assemble cache, and then mark the web control as safe. This is done by making a modification to the <safecontrols> section of the XML file, WEB.CONFIG of the web application that is going to render this control.

<SafeControls>

[snip]

<SafeControl Assembly=” MichaelHofer.SharePoint.PublishingEnhancements, Version=1.1.0.0, Culture=neutral, PublicKeyToken=7ce575c89ea427a4″ Namespace=” MichaelHofer.SharePoint.PublishingEnhancements ” Safe=”True” />

</SafeControls>

Then, in the custom master page, you have to tell SharePoint how to find the DLL. It is called ‘declaring the assembly’. Here is Mike’s example:

<%@ Register Tagprefix=”PublishingEnhancements” Namespace=”MichaelHofer.SharePoint.PublishingEnhancements” Assembly=”MichaelHofer.SharePoint.PublishingEnhancements, Version=1.1.0.0, Culture=neutral, PublicKeyToken=7ce575c89ea427a4″ %>

And now, you delete the reference to <SharePoint:CssLink> in the master page and use Mike’s control.

<PublishingEnhancements:EnhancedCssLink runat=”server”/>

Now, let’s examine the output when using this method.

<head>
[snip]
<link rel=”stylesheet” type=”text/css” href=”/_layouts/1033/styles/core.css” mce_href=”/_layouts/1033/styles/core.css” />
<link rel=”stylesheet” type=”text/css” href=”/sites/nopub/Style%20Library/pimpmysharepoint.css” mce_href=”/sites/nopub/Style%20Library/pimpmysharepoint.css” />
<link rel=”stylesheet” type=”text/css” href=”/sites/nopub/Style%20Library/anothercss.css” mce_href=”/sites/nopub/Style%20Library/anothercss.css” />
[snip]
</head>

So, CORE.CSS is now moved to the top and the world is a happy place! Or is it?

I had one problem with this method. Moving CORE.CSS unexpectedly changed the look of my branding. Then I realized the problem. Now CORE.CSS was being overwritten by every other style, and this was causing unforeseen side effects.

One other DOH problem. APPLICATION.MASTER will not reflect this change – so it has the same issue as the <link> method.

Despite this, I am going to give Mike a high cleverworkaround rating for this solution, but I am going to have to take off one point because he did not package it up into a solution :-) Mike will probably think this is terribly unfair, but on my SharePoint large farms with multiple WFE servers, if it is not a solution, it doesn’t go into production! (That’s the topic of part 4 of this series of articles).

CleverWorkaround Rating: Flawed genius – respect, man !

Over-riding CSS Files – My method

Inspired by Mike’s cleverness, I came up with an idea to improve his control. I dusted off VS2005 and added a public property called DefaultCSS. This holds the value of a CSS file I am interested in.

private string CSS;
public virtual string DefaultCSS
{
    get
    {
        return CSS;
    }
    set
    {
        CSS = value;
    }
}

Next I changed the render method, to swap the value stored in this property with CORE.CSS

protected override void Render(System.Web.UI.HtmlTextWriter output)
{
    // Let base render the stylesheets
    StringWriter sw = new StringWriter();
    base.Render(new HtmlTextWriter(sw));
    string renderedOutput = sw.ToString();
    if (this.CSS == null) {
        output.Write(renderedOutput);
    }
    else
    {
        // Split the styleSheets into an array
        string[] styleSheets = renderedOutput.Split(new char[] { ‘\n’ }, StringSplitOptions.RemoveEmptyEntries);
        if (styleSheets.Length == 0) {
            output.Write(renderedOutput);
        }
        else
        // Find reference of core and CSS property
        {
            int CSSRef = new int();
            int CoreRef = new int();
            for (int i = 0; i < styleSheets.Length; i++) {
                if (styleSheets[i].Contains(this.CSS)) {
                    CSSRef = i;
                }
                else if (styleSheets[i].Contains(”core.css”)) {
                    CoreRef = i;
                }
                else {
                    styleSheets[i